aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Scripting/WorldComm
diff options
context:
space:
mode:
authorAdam Frisby2008-04-30 21:16:36 +0000
committerAdam Frisby2008-04-30 21:16:36 +0000
commitf5c312bc3c2567449c7268a54a08a54119f58d53 (patch)
tree424668a4bbec6873ebc5b8256f3671db102f5e9c /OpenSim/Region/Environment/Modules/Scripting/WorldComm
parent* Adds the AuthbuyerID field to sqlite and makes use of it. (diff)
downloadopensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.zip
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.gz
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.bz2
opensim-SC-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.xz
* Refactored Environment/Modules directory - modules now reside in their own directory with any associated module-specific classes.
* Each module directory is currently inside one of the following category folders: Agent (Anything relating to do with Client<->Server communications.), Avatar (Anything to do with the avatar or presence inworld), Framework (Classes modules can use), Grid (Grid traffic, new OGS2 grid comms), Scripting (Scripting functions, etc), World (The enrivonment/scene, IE Sun/Tree modules.) * This should be moved into a seperate project file.
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Scripting/WorldComm')
-rw-r--r--OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs578
1 files changed, 578 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
new file mode 100644
index 0000000..a949fb6
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs
@@ -0,0 +1,578 @@
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
28using System;
29using System.Collections;
30using libsecondlife;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenSim.Region.Environment.Interfaces;
34using 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
66namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm
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 public class ListenerManager
316 {
317 //private Dictionary<int, ListenerInfo> m_listeners;
318 private Hashtable m_listeners = Hashtable.Synchronized(new Hashtable());
319 private object ListenersLock = new object();
320 private int m_MaxListeners = 100;
321
322 public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg)
323 {
324 if (m_listeners.Count < m_MaxListeners)
325 {
326 ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg);
327
328 if (isListener == null)
329 {
330 int newHandle = GetNewHandle();
331
332 if (newHandle > -1)
333 {
334 ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg);
335
336 lock (m_listeners.SyncRoot)
337 {
338 m_listeners.Add(newHandle, li);
339 }
340
341 return newHandle;
342 }
343 }
344 }
345
346 return -1;
347 }
348
349 public void Remove(int handle)
350 {
351 lock (m_listeners.SyncRoot)
352 {
353 m_listeners.Remove(handle);
354 }
355 }
356
357 public void DeleteListener(LLUUID itemID)
358 {
359 ArrayList removedListeners = new ArrayList();
360
361 lock (m_listeners.SyncRoot)
362 {
363 IDictionaryEnumerator en = m_listeners.GetEnumerator();
364 while (en.MoveNext())
365 {
366 ListenerInfo li = (ListenerInfo)en.Value;
367 if (li.GetItemID().Equals(itemID))
368 {
369 removedListeners.Add(li.GetHandle());
370 }
371 }
372 foreach (int handle in removedListeners)
373 {
374 m_listeners.Remove(handle);
375 }
376 }
377 }
378
379 private int GetNewHandle()
380 {
381 for (int i = 0; i < int.MaxValue - 1; i++)
382 {
383 if (!m_listeners.ContainsKey(i))
384 return i;
385 }
386
387 return -1;
388 }
389
390 public bool IsListener(LLUUID hostID)
391 {
392 foreach (ListenerInfo li in m_listeners.Values)
393 {
394 if (li.GetHostID().Equals(hostID))
395 return true;
396 }
397
398 return false;
399 }
400
401 public void Activate(int handle)
402 {
403
404 if (m_listeners.ContainsKey(handle))
405 {
406 lock (m_listeners.SyncRoot)
407 {
408 ListenerInfo li = (ListenerInfo)m_listeners[handle];
409 li.Activate();
410 }
411 }
412 }
413
414 public void Dectivate(int handle)
415 {
416
417 if (m_listeners.ContainsKey(handle))
418 {
419 ListenerInfo li = (ListenerInfo)m_listeners[handle];
420 li.Deactivate();
421 }
422 }
423
424 // Theres probably a more clever and efficient way to
425 // do this, maybe with regex.
426 public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name,
427 string msg)
428 {
429 bool isMatch = true;
430 lock (m_listeners.SyncRoot)
431 {
432 IDictionaryEnumerator en = m_listeners.GetEnumerator();
433 while (en.MoveNext())
434 {
435 ListenerInfo li = (ListenerInfo)en.Value;
436
437 if (li.IsActive())
438 {
439 if (li.GetHostID().Equals(listenerKey))
440 {
441 if (channel == li.GetChannel())
442 {
443 if ((li.GetID().ToString().Length > 0) &&
444 (!li.GetID().Equals(LLUUID.Zero)))
445 {
446 if (!li.GetID().ToString().Equals(sourceItemID))
447 {
448 isMatch = false;
449 }
450 }
451 if (isMatch && (li.GetName().Length > 0))
452 {
453 if (li.GetName().Equals(name))
454 {
455 isMatch = false;
456 }
457 }
458 if (isMatch)
459 {
460 return new ListenerInfo(
461 li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(),
462 li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID)
463 );
464 }
465 }
466 }
467 }
468 }
469 }
470 return null;
471 }
472
473 public ICollection GetListeners()
474 {
475 return m_listeners.Values;
476 }
477 }
478
479 public class ListenerInfo
480 {
481 private LLUUID m_itemID; // ID of the host script engine
482 private LLUUID m_hostID; // ID of the host/scene part
483 private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message
484 private int m_channel; // Channel
485 private int m_handle; // Assigned handle of this listener
486 private uint m_localID; // Local ID from script engine
487 private string m_name; // Object name to filter messages from
488 private LLUUID m_id; // ID to filter messages from
489 private string m_message; // The message
490 private bool m_active; // Listener is active or not
491
492 public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message)
493 {
494 Initialise(localID, handle, ItemID, hostID, channel, name, id, message);
495 }
496
497 public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id,
498 string message, LLUUID sourceItemID)
499 {
500 Initialise(localID, handle, ItemID, hostID, channel, name, id, message);
501 m_sourceItemID = sourceItemID;
502 }
503
504 private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name,
505 LLUUID id, string message)
506 {
507 m_handle = handle;
508 m_channel = channel;
509 m_itemID = ItemID;
510 m_hostID = hostID;
511 m_name = name;
512 m_id = id;
513 m_message = message;
514 m_active = true;
515 m_localID = localID;
516 }
517
518 public LLUUID GetItemID()
519 {
520 return m_itemID;
521 }
522
523 public LLUUID GetHostID()
524 {
525 return m_hostID;
526 }
527
528 public LLUUID GetSourceItemID()
529 {
530 return m_sourceItemID;
531 }
532
533 public int GetChannel()
534 {
535 return m_channel;
536 }
537
538 public uint GetLocalID()
539 {
540 return m_localID;
541 }
542
543 public int GetHandle()
544 {
545 return m_handle;
546 }
547
548 public string GetMessage()
549 {
550 return m_message;
551 }
552
553 public string GetName()
554 {
555 return m_name;
556 }
557
558 public bool IsActive()
559 {
560 return m_active;
561 }
562
563 public void Deactivate()
564 {
565 m_active = false;
566 }
567
568 public void Activate()
569 {
570 m_active = true;
571 }
572
573 public LLUUID GetID()
574 {
575 return m_id;
576 }
577 }
578} \ No newline at end of file