diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs | 235 |
1 files changed, 173 insertions, 62 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index f0b1e67..d83713b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs | |||
@@ -51,7 +51,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
51 | private int m_saydistance = 20; | 51 | private int m_saydistance = 20; |
52 | private int m_shoutdistance = 100; | 52 | private int m_shoutdistance = 100; |
53 | private int m_whisperdistance = 10; | 53 | private int m_whisperdistance = 10; |
54 | 54 | private List<Scene> m_scenes = new List<Scene>(); | |
55 | private List<string> FreezeCache = new List<string>(); | ||
56 | private string m_adminPrefix = ""; | ||
55 | internal object m_syncy = new object(); | 57 | internal object m_syncy = new object(); |
56 | 58 | ||
57 | internal IConfig m_config; | 59 | internal IConfig m_config; |
@@ -69,21 +71,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
69 | m_enabled = false; | 71 | m_enabled = false; |
70 | return; | 72 | return; |
71 | } | 73 | } |
74 | |||
75 | m_whisperdistance = m_config.GetInt("whisper_distance", m_whisperdistance); | ||
76 | m_saydistance = m_config.GetInt("say_distance", m_saydistance); | ||
77 | m_shoutdistance = m_config.GetInt("shout_distance", m_shoutdistance); | ||
78 | m_adminPrefix = m_config.GetString("admin_prefix", ""); | ||
72 | } | 79 | } |
73 | |||
74 | m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); | ||
75 | m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); | ||
76 | m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); | ||
77 | } | 80 | } |
78 | 81 | ||
79 | public virtual void AddRegion(Scene scene) | 82 | public virtual void AddRegion(Scene scene) |
80 | { | 83 | { |
81 | if (!m_enabled) | 84 | if (!m_enabled) return; |
82 | return; | ||
83 | 85 | ||
84 | scene.EventManager.OnNewClient += OnNewClient; | 86 | lock (m_syncy) |
85 | scene.EventManager.OnChatFromWorld += OnChatFromWorld; | 87 | { |
86 | scene.EventManager.OnChatBroadcast += OnChatBroadcast; | 88 | if (!m_scenes.Contains(scene)) |
89 | { | ||
90 | m_scenes.Add(scene); | ||
91 | scene.EventManager.OnNewClient += OnNewClient; | ||
92 | scene.EventManager.OnChatFromWorld += OnChatFromWorld; | ||
93 | scene.EventManager.OnChatBroadcast += OnChatBroadcast; | ||
94 | } | ||
95 | } | ||
87 | 96 | ||
88 | m_log.InfoFormat("[CHAT]: Initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName, | 97 | m_log.InfoFormat("[CHAT]: Initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName, |
89 | m_whisperdistance, m_saydistance, m_shoutdistance); | 98 | m_whisperdistance, m_saydistance, m_shoutdistance); |
@@ -103,12 +112,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
103 | 112 | ||
104 | public virtual void RemoveRegion(Scene scene) | 113 | public virtual void RemoveRegion(Scene scene) |
105 | { | 114 | { |
106 | if (!m_enabled) | 115 | if (!m_enabled) return; |
107 | return; | ||
108 | 116 | ||
109 | scene.EventManager.OnNewClient -= OnNewClient; | 117 | lock (m_syncy) |
110 | scene.EventManager.OnChatFromWorld -= OnChatFromWorld; | 118 | { |
111 | scene.EventManager.OnChatBroadcast -= OnChatBroadcast; | 119 | if (m_scenes.Contains(scene)) |
120 | { | ||
121 | scene.EventManager.OnNewClient -= OnNewClient; | ||
122 | scene.EventManager.OnChatFromWorld -= OnChatFromWorld; | ||
123 | scene.EventManager.OnChatBroadcast -= OnChatBroadcast; | ||
124 | m_scenes.Remove(scene); | ||
125 | } | ||
126 | } | ||
112 | } | 127 | } |
113 | 128 | ||
114 | public virtual void Close() | 129 | public virtual void Close() |
@@ -165,7 +180,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
165 | return; | 180 | return; |
166 | } | 181 | } |
167 | 182 | ||
168 | DeliverChatToAvatars(ChatSourceType.Agent, c); | 183 | if (FreezeCache.Contains(c.Sender.AgentId.ToString())) |
184 | { | ||
185 | if (c.Type != ChatTypeEnum.StartTyping || c.Type != ChatTypeEnum.StopTyping) | ||
186 | c.Sender.SendAgentAlertMessage("You may not talk as you are frozen.", false); | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | DeliverChatToAvatars(ChatSourceType.Agent, c); | ||
191 | } | ||
169 | } | 192 | } |
170 | 193 | ||
171 | public virtual void OnChatFromWorld(Object sender, OSChatMessage c) | 194 | public virtual void OnChatFromWorld(Object sender, OSChatMessage c) |
@@ -179,33 +202,61 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
179 | protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) | 202 | protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) |
180 | { | 203 | { |
181 | string fromName = c.From; | 204 | string fromName = c.From; |
205 | string fromNamePrefix = ""; | ||
182 | UUID fromID = UUID.Zero; | 206 | UUID fromID = UUID.Zero; |
183 | UUID ownerID = UUID.Zero; | 207 | UUID ownerID = UUID.Zero; |
184 | UUID targetID = c.TargetUUID; | ||
185 | string message = c.Message; | 208 | string message = c.Message; |
186 | Scene scene = (Scene)c.Scene; | 209 | IScene scene = c.Scene; |
210 | UUID destination = c.Destination; | ||
187 | Vector3 fromPos = c.Position; | 211 | Vector3 fromPos = c.Position; |
188 | Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0); | 212 | Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0); |
189 | 213 | ||
214 | bool checkParcelHide = false; | ||
215 | UUID sourceParcelID = UUID.Zero; | ||
216 | Vector3 hidePos = fromPos; | ||
217 | |||
190 | if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; | 218 | if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; |
191 | 219 | ||
192 | switch (sourceType) | 220 | switch (sourceType) |
193 | { | 221 | { |
194 | case ChatSourceType.Agent: | 222 | case ChatSourceType.Agent: |
195 | ScenePresence avatar = scene.GetScenePresence(c.Sender.AgentId); | 223 | if (!(scene is Scene)) |
224 | { | ||
225 | m_log.WarnFormat("[CHAT]: scene {0} is not a Scene object, cannot obtain scene presence for {1}", | ||
226 | scene.RegionInfo.RegionName, c.Sender.AgentId); | ||
227 | return; | ||
228 | } | ||
229 | ScenePresence avatar = (scene as Scene).GetScenePresence(c.Sender.AgentId); | ||
196 | fromPos = avatar.AbsolutePosition; | 230 | fromPos = avatar.AbsolutePosition; |
197 | fromName = avatar.Name; | 231 | fromName = avatar.Name; |
198 | fromID = c.Sender.AgentId; | 232 | fromID = c.Sender.AgentId; |
233 | if (avatar.GodLevel >= 200) | ||
234 | { // let gods speak to outside or things may get confusing | ||
235 | fromNamePrefix = m_adminPrefix; | ||
236 | checkParcelHide = false; | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | checkParcelHide = true; | ||
241 | } | ||
242 | destination = UUID.Zero; // Avatars cant "SayTo" | ||
199 | ownerID = c.Sender.AgentId; | 243 | ownerID = c.Sender.AgentId; |
200 | 244 | ||
245 | hidePos = fromPos; | ||
201 | break; | 246 | break; |
202 | 247 | ||
203 | case ChatSourceType.Object: | 248 | case ChatSourceType.Object: |
204 | fromID = c.SenderUUID; | 249 | fromID = c.SenderUUID; |
205 | 250 | ||
206 | if (c.SenderObject != null && c.SenderObject is SceneObjectPart) | 251 | if (c.SenderObject != null && c.SenderObject is SceneObjectPart) |
252 | { | ||
207 | ownerID = ((SceneObjectPart)c.SenderObject).OwnerID; | 253 | ownerID = ((SceneObjectPart)c.SenderObject).OwnerID; |
208 | 254 | if (((SceneObjectPart)c.SenderObject).ParentGroup.IsAttachment) | |
255 | { | ||
256 | checkParcelHide = true; | ||
257 | hidePos = ((SceneObjectPart)c.SenderObject).ParentGroup.AbsolutePosition; | ||
258 | } | ||
259 | } | ||
209 | break; | 260 | break; |
210 | } | 261 | } |
211 | 262 | ||
@@ -214,38 +265,68 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
214 | message = message.Substring(0, 1000); | 265 | message = message.Substring(0, 1000); |
215 | 266 | ||
216 | // m_log.DebugFormat( | 267 | // m_log.DebugFormat( |
217 | // "[CHAT]: DCTA: fromID {0} fromName {1}, region{2}, cType {3}, sType {4}, targetID {5}", | 268 | // "[CHAT]: DCTA: fromID {0} fromName {1}, region{2}, cType {3}, sType {4}", |
218 | // fromID, fromName, scene.RegionInfo.RegionName, c.Type, sourceType, targetID); | 269 | // fromID, fromName, scene.RegionInfo.RegionName, c.Type, sourceType); |
219 | 270 | ||
220 | HashSet<UUID> receiverIDs = new HashSet<UUID>(); | 271 | HashSet<UUID> receiverIDs = new HashSet<UUID>(); |
221 | 272 | ||
222 | if (targetID == UUID.Zero) | 273 | if (checkParcelHide) |
274 | { | ||
275 | checkParcelHide = false; | ||
276 | if (c.Type < ChatTypeEnum.DebugChannel && destination == UUID.Zero) | ||
277 | { | ||
278 | ILandObject srcland = (scene as Scene).LandChannel.GetLandObject(hidePos.X, hidePos.Y); | ||
279 | if (srcland != null && !srcland.LandData.SeeAVs) | ||
280 | { | ||
281 | sourceParcelID = srcland.LandData.GlobalID; | ||
282 | checkParcelHide = true; | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | foreach (Scene s in m_scenes) | ||
223 | { | 288 | { |
224 | // This should use ForEachClient, but clients don't have a position. | 289 | // This should use ForEachClient, but clients don't have a position. |
225 | // If camera is moved into client, then camera position can be used | 290 | // If camera is moved into client, then camera position can be used |
226 | scene.ForEachScenePresence( | 291 | // MT: No, it can't, as chat is heard from the avatar position, not |
292 | // the camera position. | ||
293 | |||
294 | s.ForEachScenePresence( | ||
227 | delegate(ScenePresence presence) | 295 | delegate(ScenePresence presence) |
228 | { | 296 | { |
229 | if (TrySendChatMessage( | 297 | if (destination != UUID.Zero && presence.UUID != destination) |
230 | presence, fromPos, regionPos, fromID, ownerID, fromName, c.Type, message, sourceType, false)) | 298 | return; |
231 | receiverIDs.Add(presence.UUID); | 299 | ILandObject Presencecheck = s.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); |
300 | if (Presencecheck != null) | ||
301 | { | ||
302 | // This will pass all chat from objects. Not | ||
303 | // perfect, but it will do. For now. Better | ||
304 | // than the prior behavior of muting all | ||
305 | // objects on a parcel with access restrictions | ||
306 | if (checkParcelHide) | ||
307 | { | ||
308 | if (sourceParcelID != Presencecheck.LandData.GlobalID && presence.GodLevel < 200) | ||
309 | return; | ||
310 | } | ||
311 | if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true) | ||
312 | { | ||
313 | if (destination != UUID.Zero) | ||
314 | { | ||
315 | if (TrySendChatMessage(presence, fromPos, regionPos, fromID, ownerID, fromNamePrefix + fromName, c.Type, message, sourceType, true)) | ||
316 | receiverIDs.Add(presence.UUID); | ||
317 | } | ||
318 | else | ||
319 | { | ||
320 | if (TrySendChatMessage(presence, fromPos, regionPos, fromID, ownerID, fromNamePrefix + fromName, c.Type, message, sourceType, false)) | ||
321 | receiverIDs.Add(presence.UUID); | ||
322 | } | ||
323 | } | ||
324 | } | ||
232 | } | 325 | } |
233 | ); | 326 | ); |
234 | } | 327 | } |
235 | else | 328 | |
236 | { | 329 | (scene as Scene).EventManager.TriggerOnChatToClients( |
237 | // This is a send to a specific client eg from llRegionSayTo | ||
238 | // no need to check distance etc, jand send is as say | ||
239 | ScenePresence presence = scene.GetScenePresence(targetID); | ||
240 | if (presence != null && !presence.IsChildAgent) | ||
241 | { | ||
242 | if (TrySendChatMessage( | ||
243 | presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true)) | ||
244 | receiverIDs.Add(presence.UUID); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | scene.EventManager.TriggerOnChatToClients( | ||
249 | fromID, receiverIDs, message, c.Type, fromPos, fromName, sourceType, ChatAudibleLevel.Fully); | 330 | fromID, receiverIDs, message, c.Type, fromPos, fromName, sourceType, ChatAudibleLevel.Fully); |
250 | } | 331 | } |
251 | 332 | ||
@@ -287,28 +368,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
287 | } | 368 | } |
288 | 369 | ||
289 | // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); | 370 | // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); |
290 | |||
291 | HashSet<UUID> receiverIDs = new HashSet<UUID>(); | 371 | HashSet<UUID> receiverIDs = new HashSet<UUID>(); |
292 | 372 | ||
293 | ((Scene)c.Scene).ForEachRootClient( | 373 | if (c.Scene != null) |
294 | delegate(IClientAPI client) | 374 | { |
295 | { | 375 | ((Scene)c.Scene).ForEachRootClient |
296 | // don't forward SayOwner chat from objects to | 376 | ( |
297 | // non-owner agents | 377 | delegate(IClientAPI client) |
298 | if ((c.Type == ChatTypeEnum.Owner) && | 378 | { |
299 | (null != c.SenderObject) && | 379 | // don't forward SayOwner chat from objects to |
300 | (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) | 380 | // non-owner agents |
301 | return; | 381 | if ((c.Type == ChatTypeEnum.Owner) && |
302 | 382 | (null != c.SenderObject) && | |
303 | client.SendChatMessage( | 383 | (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) |
304 | c.Message, (byte)cType, CenterOfRegion, fromName, fromID, ownerID, | 384 | return; |
305 | (byte)sourceType, (byte)ChatAudibleLevel.Fully); | 385 | |
306 | 386 | client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, fromID, | |
307 | receiverIDs.Add(client.AgentId); | 387 | (byte)sourceType, (byte)ChatAudibleLevel.Fully); |
308 | }); | 388 | receiverIDs.Add(client.AgentId); |
309 | 389 | } | |
310 | (c.Scene as Scene).EventManager.TriggerOnChatToClients( | 390 | ); |
311 | fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully); | 391 | (c.Scene as Scene).EventManager.TriggerOnChatToClients( |
392 | fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully); | ||
393 | } | ||
312 | } | 394 | } |
313 | 395 | ||
314 | /// <summary> | 396 | /// <summary> |
@@ -360,6 +442,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
360 | return true; | 442 | return true; |
361 | } | 443 | } |
362 | 444 | ||
445 | Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>(); | ||
446 | public void ParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target) | ||
447 | { | ||
448 | System.Threading.Timer Timer; | ||
449 | if (flags == 0) | ||
450 | { | ||
451 | FreezeCache.Add(target.ToString()); | ||
452 | System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen); | ||
453 | Timer = new System.Threading.Timer(timeCB, target, 30000, 0); | ||
454 | Timers.Add(target, Timer); | ||
455 | } | ||
456 | else | ||
457 | { | ||
458 | FreezeCache.Remove(target.ToString()); | ||
459 | Timers.TryGetValue(target, out Timer); | ||
460 | Timers.Remove(target); | ||
461 | Timer.Dispose(); | ||
462 | } | ||
463 | } | ||
464 | |||
465 | private void OnEndParcelFrozen(object avatar) | ||
466 | { | ||
467 | UUID target = (UUID)avatar; | ||
468 | FreezeCache.Remove(target.ToString()); | ||
469 | System.Threading.Timer Timer; | ||
470 | Timers.TryGetValue(target, out Timer); | ||
471 | Timers.Remove(target); | ||
472 | Timer.Dispose(); | ||
473 | } | ||
363 | #region SimulatorFeaturesRequest | 474 | #region SimulatorFeaturesRequest |
364 | 475 | ||
365 | static OSDInteger m_SayRange, m_WhisperRange, m_ShoutRange; | 476 | static OSDInteger m_SayRange, m_WhisperRange, m_ShoutRange; |