29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Text.RegularExpressions;
38 using OpenSim.Framework;
39 using OpenSim.Region.Framework.Interfaces;
40 using OpenSim.Region.Framework.Scenes;
93 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"WorldCommModule")]
99 private const int DEBUG_CHANNEL = 2147483647;
102 private Queue m_pending;
103 private Queue m_pendingQ;
104 private Scene m_scene;
105 private int m_whisperdistance = 10;
106 private int m_saydistance = 20;
107 private int m_shoutdistance = 100;
109 #region INonSharedRegionModule Members
115 int maxlisteners = 1000;
119 m_whisperdistance = config.Configs[
"Chat"].GetInt(
120 "whisper_distance", m_whisperdistance);
121 m_saydistance = config.Configs[
"Chat"].GetInt(
122 "say_distance", m_saydistance);
123 m_shoutdistance = config.Configs[
"Chat"].GetInt(
124 "shout_distance", m_shoutdistance);
125 maxlisteners = config.Configs[
"LL-Functions"].GetInt(
126 "max_listens_per_region", maxlisteners);
127 maxhandles = config.Configs[
"LL-Functions"].GetInt(
128 "max_listens_per_script", maxhandles);
133 if (maxlisteners < 1) maxlisteners = int.MaxValue;
134 if (maxhandles < 1) maxhandles = int.MaxValue;
136 m_pendingQ =
new Queue();
137 m_pending = Queue.Synchronized(m_pendingQ);
147 m_scene.RegisterModuleInterface<
IWorldComm>(
this);
148 m_scene.EventManager.OnChatFromClient += DeliverClientMessage;
149 m_scene.EventManager.OnChatBroadcast += DeliverClientMessage;
156 if (scene != m_scene)
159 m_scene.UnregisterModuleInterface<
IWorldComm>(
this);
160 m_scene.EventManager.OnChatBroadcast -= DeliverClientMessage;
161 m_scene.EventManager.OnChatBroadcast -= DeliverClientMessage;
170 get {
return "WorldCommModule"; }
173 public Type ReplaceableInterface {
get {
return null; } }
177 #region IWorldComm Members
179 public int ListenerCount
183 return m_listenerManager.ListenerCount;
203 public int Listen(uint localID, UUID itemID, UUID hostID,
int channel,
204 string name, UUID
id,
string msg)
206 return m_listenerManager.AddListener(localID, itemID, hostID,
207 channel, name, id, msg);
229 public int Listen(uint localID, UUID itemID, UUID hostID,
int channel,
230 string name, UUID
id,
string msg,
int regexBitfield)
232 return m_listenerManager.AddListener(localID, itemID, hostID,
233 channel, name, id, msg, regexBitfield);
246 m_listenerManager.Activate(itemID, handle);
247 else if (active == 0)
248 m_listenerManager.Dectivate(itemID, handle);
258 m_listenerManager.Remove(itemID, handle);
268 m_listenerManager.DeleteListener(itemID);
272 protected static Vector3 CenterOfRegion =
new Vector3(128, 128, 20);
280 if ((source = m_scene.GetSceneObjectPart(
id)) != null)
281 position = source.AbsolutePosition;
282 else if ((avatar = m_scene.GetScenePresence(
id)) != null)
283 position = avatar.AbsolutePosition;
285 position = CenterOfRegion;
289 DeliverMessage(type, channel, name,
id, msg, position);
306 string name, UUID
id,
string msg, Vector3 position)
316 in m_listenerManager.GetListeners(
UUID.Zero, channel,
328 double dis = Util.GetDistanceTo(sPart.AbsolutePosition,
332 case ChatTypeEnum.Whisper:
333 if (dis < m_whisperdistance)
337 case ChatTypeEnum.Say:
338 if (dis < m_saydistance)
342 case ChatTypeEnum.Shout:
343 if (dis < m_shoutdistance)
347 case ChatTypeEnum.Region:
372 public void DeliverMessageTo(UUID target,
int channel, Vector3 pos,
string name, UUID
id,
string msg)
374 if (channel == DEBUG_CHANNEL)
386 m_scene.SimChat(Utils.StringToBytes(msg),
ChatTypeEnum.Broadcast, 0, pos, name,
id, target,
false,
false);
394 List<SceneObjectGroup> attachments = sp.GetAttachments();
396 if (attachments.Count == 0)
400 List<UUID> targets =
new List<UUID>();
404 targets.Add(sog.UUID);
408 foreach (
ListenerInfo li
in m_listenerManager.GetListeners(
UUID.Zero, channel, name,
id, msg))
413 if (m_scene.GetSceneObjectPart(li.
GetHostID()) == null)
427 foreach (
ListenerInfo li
in m_listenerManager.GetListeners(
UUID.Zero, channel, name,
id, msg))
448 lock (m_pending.SyncRoot)
450 m_pending.Enqueue(li);
460 return (m_pending.Count > 0);
471 lock (m_pending.SyncRoot)
487 private void DeliverClientMessage(Object sender,
OSChatMessage e)
503 return m_listenerManager.GetSerializationData(itemID);
509 m_listenerManager.AddFromData(localID, itemID, hostID, data);
515 private Dictionary<int, List<ListenerInfo>> m_listeners =
516 new Dictionary<int, List<ListenerInfo>>();
517 private int m_maxlisteners;
518 private int m_maxhandles;
519 private int m_curlisteners;
524 public int ListenerCount
529 return m_listeners.Count;
535 m_maxlisteners = maxlisteners;
536 m_maxhandles = maxhandles;
541 int channel,
string name, UUID
id,
string msg)
543 return AddListener(localID, itemID, hostID, channel, name,
id,
548 int channel,
string name, UUID
id,
string msg,
552 List<ListenerInfo> coll = GetListeners(itemID, channel, name,
id,
559 return coll[0].GetHandle();
562 if (m_curlisteners < m_maxlisteners)
566 int newHandle = GetNewHandle(itemID);
571 itemID, hostID, channel, name,
id, msg,
574 List<ListenerInfo> listeners;
575 if (!m_listeners.TryGetValue(
576 channel, out listeners))
578 listeners =
new List<ListenerInfo>();
579 m_listeners.Add(channel, listeners);
591 public void Remove(UUID itemID,
int handle)
595 foreach (KeyValuePair<
int, List<ListenerInfo>> lis
603 lis.Value.Remove(li);
604 if (lis.Value.Count == 0)
606 m_listeners.Remove(lis.Key);
619 List<int> emptyChannels =
new List<int>();
620 List<ListenerInfo> removedListeners =
new List<ListenerInfo>();
624 foreach (KeyValuePair<
int, List<ListenerInfo>> lis
633 removedListeners.Add(li);
638 lis.Value.Remove(li);
641 removedListeners.Clear();
642 if (lis.Value.Count == 0)
645 emptyChannels.Add(lis.Key);
648 foreach (
int channel
in emptyChannels)
650 m_listeners.Remove(channel);
659 foreach (KeyValuePair<
int, List<ListenerInfo>> lis
680 foreach (KeyValuePair<
int, List<ListenerInfo>> lis
703 private int GetNewHandle(UUID itemID)
705 List<int> handles =
new List<int>();
708 foreach (KeyValuePair<
int, List<ListenerInfo>> lis
in m_listeners)
713 handles.Add(li.GetHandle());
718 for (
int i = 1; i <= m_maxhandles; i++)
720 if (!handles.Contains(i))
729 #region Constants for the bitfield parameter of osListenRegex
734 public const int OS_LISTEN_REGEX_NAME = 0x1;
739 public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
759 string name, UUID
id,
string msg)
761 List<ListenerInfo> collection =
new List<ListenerInfo>();
765 List<ListenerInfo> listeners;
766 if (!m_listeners.TryGetValue(channel, out listeners))
777 if (!itemID.Equals(
UUID.Zero) &&
778 !li.GetItemID().Equals(itemID))
782 if (li.
GetName().Length > 0 && (
783 ((li.RegexBitfield & OS_LISTEN_REGEX_NAME) != OS_LISTEN_REGEX_NAME && !li.
GetName().Equals(name)) ||
784 ((li.RegexBitfield & OS_LISTEN_REGEX_NAME) == OS_LISTEN_REGEX_NAME && !Regex.IsMatch(name, li.
GetName()))
789 if (!li.
GetID().Equals(UUID.Zero) && !li.
GetID().Equals(id))
794 ((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) != OS_LISTEN_REGEX_MESSAGE && !li.
GetMessage().Equals(msg)) ||
795 ((li.RegexBitfield & OS_LISTEN_REGEX_MESSAGE) == OS_LISTEN_REGEX_MESSAGE && !Regex.IsMatch(msg, li.
GetMessage()))
808 List<Object> data =
new List<Object>();
812 foreach (List<ListenerInfo> list
in m_listeners.Values)
821 return (
Object[])data.ToArray();
829 int dataItemLength = 6;
831 while (idx < data.Length)
833 dataItemLength = (idx + 7 == data.Length || (idx + 7 < data.Length && data[idx + 7] is bool)) ? 7 : 6;
834 item =
new Object[dataItemLength];
835 Array.Copy(data, idx, item, 0, dataItemLength);
838 ListenerInfo.FromData(localID, itemID, hostID, item);
842 if (!m_listeners.ContainsKey((
int)item[2]))
844 m_listeners.Add((int)item[2],
845 new List<ListenerInfo>());
847 m_listeners[(int)item[2]].Add(info);
850 idx += dataItemLength;
860 private bool m_active;
865 private int m_handle;
870 private uint m_localID;
875 private UUID m_itemID;
880 private UUID m_hostID;
885 private int m_channel;
895 private string m_name;
900 private string m_message;
903 UUID hostID,
int channel,
string name, UUID
id,
906 Initialise(handle, localID, ItemID, hostID, channel, name,
id,
911 UUID hostID,
int channel,
string name, UUID
id,
912 string message,
int regexBitfield)
914 Initialise(handle, localID, ItemID, hostID, channel, name,
id,
915 message, regexBitfield);
921 Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID,
922 li.m_channel, name,
id, message, 0);
926 string message,
int regexBitfield)
928 Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID,
929 li.m_channel, name,
id, message, regexBitfield);
932 private void Initialise(
int handle, uint localID, UUID ItemID,
933 UUID hostID,
int channel,
string name, UUID
id,
934 string message,
int regexBitfield)
945 RegexBitfield = regexBitfield;
958 data[6] = RegexBitfield;
964 UUID hostID, Object[] data)
967 ItemID, hostID, (
int)data[2], (
string)data[3],
968 (
UUID)data[4], (
string)data[5]);
969 linfo.m_active = (bool)data[0];
970 if (data.Length >= 7)
972 linfo.RegexBitfield = (int)data[6];
1033 public int RegexBitfield {
get;
private set; }
void AddFromData(uint localID, UUID itemID, UUID hostID, Object[] data)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
int Listen(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
Create a listen event callback with the specified filters. The parameters localID,itemID are needed to uniquely identify the script during 'peek' time. Parameter hostID is needed to determine the position of the script.
ListenerInfo(ListenerInfo li, string name, UUID id, string message, int regexBitfield)
void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg)
This method scans over the objects which registered an interest in listen callbacks. For everyone it finds, it checks if it fits the given filter. If it does, then enqueue the message for delivery to the objects listen event handler. The enqueued ListenerInfo no longer has filter values, but the actually trigged values. Objects that do an llSay have their messages delivered here and for nearby avatars, the OnChatFromClient event is used.
void DeliverMessageTo(UUID target, int channel, Vector3 pos, string name, UUID id, string msg)
Delivers the message to a scene entity.
void QueueMessage(ListenerInfo li)
ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message, int regexBitfield)
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
Object[] GetSerializationData()
IClientAPI Sender
The client responsible for sending the message, or null.
ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message)
Object[] GetSerializationData(UUID itemID)
string Name
Returns the full name of the agent/avatar represented by this client
int Listen(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg, int regexBitfield)
Create a listen event callback with the specified filters. The parameters localID,itemID are needed to uniquely identify the script during 'peek' time. Parameter hostID is needed to determine the position of the script.
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void CreateFromData(uint localID, UUID itemID, UUID hostID, Object[] data)
bool HasMessages()
Are there any listen events ready to be dispatched?
string Message
The message sent by the user
List< ListenerInfo > GetListeners(UUID itemID, int channel, string name, UUID id, string msg)
Get listeners matching the input parameters.
void ListenControl(UUID itemID, int handle, int active)
Sets the listen event with handle as active (active = TRUE) or inactive (active = FALSE)...
void ListenRemove(UUID itemID, int handle)
Removes the listen event callback with handle
void DeleteListener(UUID itemID)
Removes all listen event callbacks for the given itemID (script engine)
bool IsDeleted
Signals whether this entity was in a scene but has since been removed from it.
int AddListener(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
Object[] GetSerializationData(UUID itemID)
string From
The name of the sender (needed for scripts)
void Dectivate(UUID itemID, int handle)
int AddListener(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg, int regexBitfield)
void Activate(UUID itemID, int handle)
ChatTypeEnum Type
The type of message, eg say, shout, broadcast.
static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
Interactive OpenSim region server
void DeleteListener(UUID itemID)
IWorldCommListenerInfo GetNextMessage()
Pop the first availlable listen event from the queue
void Remove(UUID itemID, int handle)
ListenerManager(int maxlisteners, int maxhandles)
ListenerInfo(ListenerInfo li, string name, UUID id, string message)
Vector3 Position
The position of the sender at the time of the message broadcast.
int Channel
Which channel was this message sent on? Different channels may have different listeners. Public chat is on channel zero.
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void DeliverMessage(ChatTypeEnum type, int channel, string name, UUID id, string msg, Vector3 position)
This method scans over the objects which registered an interest in listen callbacks. For everyone it finds, it checks if it fits the given filter. If it does, then enqueue the message for delivery to the objects listen event handler. The enqueued ListenerInfo no longer has filter values, but the actually trigged values. Objects that do an llSay have their messages delivered here and for nearby avatars, the OnChatFromClient event is used.
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...