From 180be7de07014aa33bc6066f12a0819b731c1c9d Mon Sep 17 00:00:00 2001 From: Dr Scofield Date: Tue, 10 Feb 2009 13:10:57 +0000 Subject: this is step 2 of 2 of the OpenSim.Region.Environment refactor. NOTHING has been deleted or moved off to forge at this point. what has happened is that OpenSim.Region.Environment.Modules has been split in two: - OpenSim.Region.CoreModules: all those modules that are either directly or indirectly referenced from other OpenSim packages, or that provide functionality that the OpenSim developer community considers core functionality: CoreModules/Agent/AssetTransaction CoreModules/Agent/Capabilities CoreModules/Agent/TextureDownload CoreModules/Agent/TextureSender CoreModules/Agent/TextureSender/Tests CoreModules/Agent/Xfer CoreModules/Avatar/AvatarFactory CoreModules/Avatar/Chat/ChatModule CoreModules/Avatar/Combat CoreModules/Avatar/Currency/SampleMoney CoreModules/Avatar/Dialog CoreModules/Avatar/Friends CoreModules/Avatar/Gestures CoreModules/Avatar/Groups CoreModules/Avatar/InstantMessage CoreModules/Avatar/Inventory CoreModules/Avatar/Inventory/Archiver CoreModules/Avatar/Inventory/Transfer CoreModules/Avatar/Lure CoreModules/Avatar/ObjectCaps CoreModules/Avatar/Profiles CoreModules/Communications/Local CoreModules/Communications/REST CoreModules/Framework/EventQueue CoreModules/Framework/InterfaceCommander CoreModules/Hypergrid CoreModules/InterGrid CoreModules/Scripting/DynamicTexture CoreModules/Scripting/EMailModules CoreModules/Scripting/HttpRequest CoreModules/Scripting/LoadImageURL CoreModules/Scripting/VectorRender CoreModules/Scripting/WorldComm CoreModules/Scripting/XMLRPC CoreModules/World/Archiver CoreModules/World/Archiver/Tests CoreModules/World/Estate CoreModules/World/Land CoreModules/World/Permissions CoreModules/World/Serialiser CoreModules/World/Sound CoreModules/World/Sun CoreModules/World/Terrain CoreModules/World/Terrain/DefaultEffects CoreModules/World/Terrain/DefaultEffects/bin CoreModules/World/Terrain/DefaultEffects/bin/Debug CoreModules/World/Terrain/Effects CoreModules/World/Terrain/FileLoaders CoreModules/World/Terrain/FloodBrushes CoreModules/World/Terrain/PaintBrushes CoreModules/World/Terrain/Tests CoreModules/World/Vegetation CoreModules/World/Wind CoreModules/World/WorldMap - OpenSim.Region.OptionalModules: all those modules that are not core modules: OptionalModules/Avatar/Chat/IRC-stuff OptionalModules/Avatar/Concierge OptionalModules/Avatar/Voice/AsterixVoice OptionalModules/Avatar/Voice/SIPVoice OptionalModules/ContentManagementSystem OptionalModules/Grid/Interregion OptionalModules/Python OptionalModules/SvnSerialiser OptionalModules/World/NPC OptionalModules/World/TreePopulator --- .../Region/CoreModules/Avatar/Chat/ChatModule.cs | 287 +++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs (limited to 'OpenSim/Region/CoreModules/Avatar/Chat') diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs new file mode 100644 index 0000000..f036faf --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs @@ -0,0 +1,287 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Sockets; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading; +using OpenMetaverse; +using log4net; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.Avatar.Chat +{ + public class ChatModule : IRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private const int DEBUG_CHANNEL = 2147483647; + + private bool m_enabled = true; + private int m_saydistance = 30; + private int m_shoutdistance = 100; + private int m_whisperdistance = 10; + private List m_scenes = new List(); + + internal object m_syncInit = new object(); + + #region IRegionModule Members + public virtual void Initialise(Scene scene, IConfigSource config) + { + // wrap this in a try block so that defaults will work if + // the config file doesn't specify otherwise. + try + { + m_enabled = config.Configs["Chat"].GetBoolean("enabled", m_enabled); + if (!m_enabled) return; + + m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); + m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); + m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); + } + catch (Exception) + { + } + + lock (m_syncInit) + { + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnChatFromWorld += OnChatFromWorld; + scene.EventManager.OnChatBroadcast += OnChatBroadcast; + } + } + + m_log.InfoFormat("[CHAT] initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName, + m_whisperdistance, m_saydistance, m_shoutdistance); + } + public virtual void PostInitialise() + { + } + + public virtual void Close() + { + } + + public virtual string Name + { + get { return "ChatModule"; } + } + + public virtual bool IsSharedModule + { + get { return true; } + } + + #endregion + + + public virtual void OnNewClient(IClientAPI client) + { + client.OnChatFromClient += OnChatFromClient; + } + + protected OSChatMessage FixPositionOfChatMessage(OSChatMessage c) + { + ScenePresence avatar; + Scene scene = (Scene)c.Scene; + if ((avatar = scene.GetScenePresence(c.Sender.AgentId)) != null) + c.Position = avatar.AbsolutePosition; + + return c; + } + + public virtual void OnChatFromClient(Object sender, OSChatMessage c) + { + c = FixPositionOfChatMessage(c); + + // redistribute to interested subscribers + Scene scene = (Scene)c.Scene; + scene.EventManager.TriggerOnChatFromClient(sender, c); + + // early return if not on public or debug channel + if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL) return; + + // sanity check: + if (c.Sender == null) + { + m_log.ErrorFormat("[CHAT] OnChatFromClient from {0} has empty Sender field!", sender); + return; + } + + DeliverChatToAvatars(ChatSourceType.Agent, c); + } + + public virtual void OnChatFromWorld(Object sender, OSChatMessage c) + { + // early return if not on public or debug channel + if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL) return; + + DeliverChatToAvatars(ChatSourceType.Object, c); + } + + protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) + { + string fromName = c.From; + UUID fromID = UUID.Zero; + string message = c.Message; + IScene scene = c.Scene; + Vector3 fromPos = c.Position; + Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, + scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); + + if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; + + switch (sourceType) + { + case ChatSourceType.Agent: + if (!(scene is Scene)) + { + m_log.WarnFormat("[CHAT]: scene {0} is not a Scene object, cannot obtain scene presence for {1}", + scene.RegionInfo.RegionName, c.Sender.AgentId); + return; + } + ScenePresence avatar = (scene as Scene).GetScenePresence(c.Sender.AgentId); + fromPos = avatar.AbsolutePosition; + fromName = avatar.Name; + fromID = c.Sender.AgentId; + + break; + + case ChatSourceType.Object: + fromID = c.SenderUUID; + + break; + } + + // TODO: iterate over message + if (message.Length >= 1000) // libomv limit + message = message.Substring(0, 1000); + + // m_log.DebugFormat("[CHAT]: DCTA: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, c.Type, sourceType); + + foreach (Scene s in m_scenes) + { + s.ForEachScenePresence(delegate(ScenePresence presence) + { + TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, + c.Type, message, sourceType); + }); + } + } + + + static private Vector3 CenterOfRegion = new Vector3(128, 128, 30); + public virtual void OnChatBroadcast(Object sender, OSChatMessage c) + { + // unless the chat to be broadcast is of type Region, we + // drop it if its channel is neither 0 nor DEBUG_CHANNEL + if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL && c.Type != ChatTypeEnum.Region) return; + + ChatTypeEnum cType = c.Type; + if (c.Channel == DEBUG_CHANNEL) + cType = ChatTypeEnum.DebugChannel; + + if (cType == ChatTypeEnum.Region) + cType = ChatTypeEnum.Say; + + if (c.Message.Length > 1100) + c.Message = c.Message.Substring(0, 1000); + + // broadcast chat works by redistributing every incoming chat + // message to each avatar in the scene. + string fromName = c.From; + + UUID fromID = UUID.Zero; + ChatSourceType sourceType = ChatSourceType.Object; + if (null != c.Sender) + { + ScenePresence avatar = (c.Scene as Scene).GetScenePresence(c.Sender.AgentId); + fromID = c.Sender.AgentId; + fromName = avatar.Name; + sourceType = ChatSourceType.Agent; + } + + // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); + + ((Scene)c.Scene).ForEachScenePresence( + delegate(ScenePresence presence) + { + // ignore chat from child agents + if (presence.IsChildAgent) return; + + IClientAPI client = presence.ControllingClient; + + // don't forward SayOwner chat from objects to + // non-owner agents + if ((c.Type == ChatTypeEnum.Owner) && + (null != c.SenderObject) && + (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) + return; + + client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, + (byte)sourceType, (byte)ChatAudibleLevel.Fully); + }); + } + + + protected virtual void TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos, + UUID fromAgentID, string fromName, ChatTypeEnum type, + string message, ChatSourceType src) + { + // don't send stuff to child agents + if (presence.IsChildAgent) return; + + Vector3 fromRegionPos = fromPos + regionPos; + Vector3 toRegionPos = presence.AbsolutePosition + + new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, + presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); + + int dis = Math.Abs((int) Util.GetDistanceTo(toRegionPos, fromRegionPos)); + + if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance || + type == ChatTypeEnum.Say && dis > m_saydistance || + type == ChatTypeEnum.Shout && dis > m_shoutdistance) + { + return; + } + + // TODO: should change so the message is sent through the avatar rather than direct to the ClientView + presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName, + fromAgentID,(byte)src,(byte)ChatAudibleLevel.Fully); + } + } +} -- cgit v1.1