From 55400ff7be55b1c8dbededca68e6fce42cd6ce0f Mon Sep 17 00:00:00 2001 From: teravus Date: Fri, 23 Aug 2013 00:28:36 -0500 Subject: [PATCH 01/12] * This increases accuracy when border crossing (the reason is.. the border crossing code will use velocity to predict where the object should be, so setting it to zero. It still looses about 0.0045 per loop. --- OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index d773ee7f28..f96b56a54b 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -644,8 +644,8 @@ namespace OpenSim.Region.Framework.Scenes // m_group.AbsolutePosition += motionThisFrame; m_nextPosition = m_group.AbsolutePosition + motionThisFrame; m_group.AbsolutePosition = m_nextPosition; - - //m_group.RootPart.Velocity = v; + if ((m_group.AbsolutePosition.X < 10 || m_group.AbsolutePosition.Y < 10 || m_group.AbsolutePosition.X > Constants.RegionSize - 10 || m_group.AbsolutePosition.Y > Constants.RegionSize - 10)) + m_group.RootPart.Velocity = v; update = true; } @@ -736,12 +736,12 @@ namespace OpenSim.Region.Framework.Scenes m_waitingCrossing = true; // to remove / retune to smoth crossings - if (m_group.RootPart.Velocity != Vector3.Zero) - { - m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); + //if (m_group.RootPart.Velocity != Vector3.Zero) + //{ + // m_group.RootPart.Velocity = Vector3.Zero; + // m_group.SendGroupRootTerseUpdate(); // m_group.RootPart.ScheduleTerseUpdate(); - } + //} } public void CrossingFailure() From 58359788a915afd80d5fb2ff9f069cda6c841c81 Mon Sep 17 00:00:00 2001 From: teravus Date: Sat, 24 Aug 2013 05:54:08 -0500 Subject: [PATCH 02/12] Revert "* This increases accuracy when border crossing (the reason is.. the border crossing code will use velocity to predict where the object should be, so setting it to zero. It still looses about 0.0045 per loop." This reverts commit 55400ff7be55b1c8dbededca68e6fce42cd6ce0f. --- OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index f96b56a54b..d773ee7f28 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -644,8 +644,8 @@ namespace OpenSim.Region.Framework.Scenes // m_group.AbsolutePosition += motionThisFrame; m_nextPosition = m_group.AbsolutePosition + motionThisFrame; m_group.AbsolutePosition = m_nextPosition; - if ((m_group.AbsolutePosition.X < 10 || m_group.AbsolutePosition.Y < 10 || m_group.AbsolutePosition.X > Constants.RegionSize - 10 || m_group.AbsolutePosition.Y > Constants.RegionSize - 10)) - m_group.RootPart.Velocity = v; + + //m_group.RootPart.Velocity = v; update = true; } @@ -736,12 +736,12 @@ namespace OpenSim.Region.Framework.Scenes m_waitingCrossing = true; // to remove / retune to smoth crossings - //if (m_group.RootPart.Velocity != Vector3.Zero) - //{ - // m_group.RootPart.Velocity = Vector3.Zero; - // m_group.SendGroupRootTerseUpdate(); + if (m_group.RootPart.Velocity != Vector3.Zero) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); // m_group.RootPart.ScheduleTerseUpdate(); - //} + } } public void CrossingFailure() From 01c3be27460fd3f28efd17b8d6606b883350f653 Mon Sep 17 00:00:00 2001 From: teravus Date: Sat, 24 Aug 2013 05:55:53 -0500 Subject: [PATCH 03/12] * Fix a null ref that causes a stack unwind when crossing borders. Less stack unwinding.. the faster it goes. * Tweak XEngine so that it's partially functional again. It's still not great, but basic things work. --- .../CoreModules/Avatar/Combat/CombatModule.cs | 2 + .../Shared/Instance/ScriptInstance.cs | 1 + .../Region/ScriptEngine/XEngine/XEngine.cs | 56 +++++++++++++++---- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs index 343cdb5c1e..c52d586fa1 100644 --- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs @@ -182,6 +182,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule try { ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); + if (obj == null) + return; if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0 || avatar.Scene.RegionInfo.RegionSettings.AllowDamage) { diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 26850c4582..a2ac9c59f4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -231,6 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance ItemID = ScriptTask.ItemID; AssetID = ScriptTask.AssetID; } + LocalID = part.LocalId; PrimName = part.ParentGroup.Name; StartParam = startParam; diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 17243ab134..04a4e53618 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1316,13 +1316,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine ScriptInstance instance = null; // Create the object record + UUID appDomain = assetID; + + + lockScriptsForRead(true); if ((!m_Scripts.ContainsKey(itemID)) || (m_Scripts[itemID].AssetID != assetID)) { lockScriptsForRead(false); - - UUID appDomain = assetID; + instance = new ScriptInstance(this, part, + item, + startParam, postOnRez, + m_MaxScriptQueue); + + if (part.ParentGroup.IsAttachment) appDomain = part.ParentGroup.RootPart.UUID; @@ -1345,9 +1353,39 @@ namespace OpenSim.Region.ScriptEngine.XEngine sandbox = AppDomain.CreateDomain( m_Scene.RegionInfo.RegionID.ToString(), evidence, appSetup); - m_AppDomains[appDomain].AssemblyResolve += - new ResolveEventHandler( - AssemblyResolver.OnAssemblyResolve); + if (m_AppDomains.ContainsKey(appDomain)) + { + m_AppDomains[appDomain].AssemblyResolve += + new ResolveEventHandler( + AssemblyResolver.OnAssemblyResolve); + if (m_DomainScripts.ContainsKey(appDomain)) + { + m_DomainScripts[appDomain].Add(itemID); + } + else + { + m_DomainScripts.Add(appDomain, new List()); + m_DomainScripts[appDomain].Add(itemID); + } + } + else + { + m_AppDomains.Add(appDomain, sandbox); + m_AppDomains[appDomain].AssemblyResolve += + new ResolveEventHandler( + AssemblyResolver.OnAssemblyResolve); + if (m_DomainScripts.ContainsKey(appDomain)) + { + m_DomainScripts[appDomain].Add(itemID); + } + else + { + m_DomainScripts.Add(appDomain, new List()); + m_DomainScripts[appDomain].Add(itemID); + } + + } + } else { @@ -1373,12 +1411,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine return false; } } - m_DomainScripts[appDomain].Add(itemID); - - instance = new ScriptInstance(this, part, - item, - startParam, postOnRez, - m_MaxScriptQueue); + instance.Load(m_AppDomains[appDomain], assembly, stateSource); // m_log.DebugFormat( @@ -1502,6 +1535,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (handlerObjectRemoved != null) { SceneObjectPart part = m_Scene.GetSceneObjectPart(localID); + if (part != null) handlerObjectRemoved(part.UUID); } From e0399ccaec68889c12e4679b4d62142b49b379df Mon Sep 17 00:00:00 2001 From: teravus Date: Sat, 24 Aug 2013 18:55:21 -0500 Subject: [PATCH 04/12] * This fixes the border crossing offsets by storing the final keyframe location in the hijacked variable KeyFrame.AngularVelocity. When steps in OnTimer <= 0.0, normalize the final position by Constants.RegionSize and move the object there. The hack here is KeyFrame.AngularVelocity probably isn't the right name for this variable because it's the un-mucked with keyframe position. When you determine the feasibility of changing the name without affecting the serialization of existing objects in world... It's simply a name change to KeyFrame.FinalPosition or something proper. --- .../Region/Framework/Scenes/KeyframeMotion.cs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index d773ee7f28..d9df95c68e 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -478,6 +478,7 @@ namespace OpenSim.Region.Framework.Scenes k.Position = pos; // k.Velocity = Vector3.Zero; } + k.AngularVelocity = (Vector3)k.Position; k.StartRotation = rot; if (k.Rotation.HasValue) @@ -612,13 +613,13 @@ namespace OpenSim.Region.Framework.Scenes // Do the frame processing double steps = (double)m_currentFrame.TimeMS / tickDuration; - + if (steps <= 0.0) { m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.AngularVelocity = Vector3.Zero; - m_nextPosition = (Vector3)m_currentFrame.Position; + m_nextPosition = NormalizeVector(m_currentFrame.AngularVelocity); m_group.AbsolutePosition = m_nextPosition; // we are sending imediate updates, no doing force a extra terseUpdate @@ -706,7 +707,26 @@ namespace OpenSim.Region.Framework.Scenes m_group.SendGroupRootTerseUpdate(); } } + private Vector3 NormalizeVector(Vector3? pPosition) + { + if (pPosition == null) + return Vector3.Zero; + Vector3 tmp = (Vector3) pPosition; + + while (tmp.X > Constants.RegionSize) + tmp.X -= Constants.RegionSize; + while (tmp.X < 0) + tmp.X += Constants.RegionSize; + while (tmp.Y > Constants.RegionSize) + tmp.Y -= Constants.RegionSize; + while (tmp.Y < 0) + tmp.Y += Constants.RegionSize; + + return tmp; + + + } public Byte[] Serialize() { StopTimer(); From f7378829c3da999fcd200a5d0e6189a563cbda39 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 25 Aug 2013 06:26:56 +0200 Subject: [PATCH 05/12] Fix the root cause of keyframe motion region crossing offset - UpdateSceneObject was being called twice on each crossing. --- .../Region/Framework/Scenes/KeyframeMotion.cs | 22 +------------------ OpenSim/Region/Framework/Scenes/Scene.cs | 6 +++-- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index d9df95c68e..276b61fa1c 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -478,7 +478,6 @@ namespace OpenSim.Region.Framework.Scenes k.Position = pos; // k.Velocity = Vector3.Zero; } - k.AngularVelocity = (Vector3)k.Position; k.StartRotation = rot; if (k.Rotation.HasValue) @@ -619,7 +618,7 @@ namespace OpenSim.Region.Framework.Scenes m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.AngularVelocity = Vector3.Zero; - m_nextPosition = NormalizeVector(m_currentFrame.AngularVelocity); + m_nextPosition = (Vector3)m_currentFrame.Position; m_group.AbsolutePosition = m_nextPosition; // we are sending imediate updates, no doing force a extra terseUpdate @@ -707,26 +706,7 @@ namespace OpenSim.Region.Framework.Scenes m_group.SendGroupRootTerseUpdate(); } } - private Vector3 NormalizeVector(Vector3? pPosition) - { - if (pPosition == null) - return Vector3.Zero; - Vector3 tmp = (Vector3) pPosition; - - while (tmp.X > Constants.RegionSize) - tmp.X -= Constants.RegionSize; - while (tmp.X < 0) - tmp.X += Constants.RegionSize; - while (tmp.Y > Constants.RegionSize) - tmp.Y -= Constants.RegionSize; - while (tmp.Y < 0) - tmp.Y += Constants.RegionSize; - - return tmp; - - - } public Byte[] Serialize() { StopTimer(); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 2b58795656..b189599f10 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2802,8 +2802,10 @@ namespace OpenSim.Region.Framework.Scenes newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); newObject.ResumeScripts(); - if (newObject.RootPart.KeyframeMotion != null) - newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject); + // AddSceneObject already does this and doing it again messes + // up region crossings, so don't. + //if (newObject.RootPart.KeyframeMotion != null) + // newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject); } // Do this as late as possible so that listeners have full access to the incoming object From 823e8b5d19099fcc560cefeec5943b9a19571a37 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 7 Sep 2013 17:57:02 +0200 Subject: [PATCH 06/12] Add support for simple external CAPS texture services --- .../Linden/Caps/GetTextureModule.cs | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index a42c96c981..057014425d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs @@ -77,6 +77,8 @@ namespace OpenSim.Region.ClientStack.Linden private Dictionary m_capsDict = new Dictionary(); private static Thread[] m_workerThreads = null; + private string m_Url = "localhost"; + private static OpenMetaverse.BlockingQueue m_queue = new OpenMetaverse.BlockingQueue(); @@ -86,6 +88,9 @@ namespace OpenSim.Region.ClientStack.Linden public void Initialise(IConfigSource source) { + IConfig config = source.Configs["ClientStack.LindenCaps"]; + if (config != null) + m_Url = config.GetString("Cap_GetTexture", "localhost"); } public void AddRegion(Scene s) @@ -343,27 +348,34 @@ namespace OpenSim.Region.ClientStack.Linden private void RegisterCaps(UUID agentID, Caps caps) { - string capUrl = "/CAPS/" + UUID.Random() + "/"; - - // Register this as a poll service - PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene); - - args.Type = PollServiceEventArgs.EventType.Texture; - MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); - - string hostName = m_scene.RegionInfo.ExternalHostName; - uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; - string protocol = "http"; - - if (MainServer.Instance.UseSSL) + if (m_Url == "localhost") { - hostName = MainServer.Instance.SSLCommonName; - port = MainServer.Instance.SSLPort; - protocol = "https"; + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + // Register this as a poll service + PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene); + + args.Type = PollServiceEventArgs.EventType.Texture; + MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); + + string hostName = m_scene.RegionInfo.ExternalHostName; + uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; + string protocol = "http"; + + if (MainServer.Instance.UseSSL) + { + hostName = MainServer.Instance.SSLCommonName; + port = MainServer.Instance.SSLPort; + protocol = "https"; + } + caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + m_pollservices[agentID] = args; + m_capsDict[agentID] = capUrl; + } + else + { + caps.RegisterHandler("GetTexture", m_Url); } - caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); - m_pollservices[agentID] = args; - m_capsDict[agentID] = capUrl; } private void DeregisterCaps(UUID agentID, Caps caps) From 66715a69a73d78c2da9b68b8776a02195bb2e953 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 7 Sep 2013 17:57:53 +0200 Subject: [PATCH 07/12] Add two argument constructor to GridInstantMessage --- OpenSim/Framework/GridInstantMessage.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/OpenSim/Framework/GridInstantMessage.cs b/OpenSim/Framework/GridInstantMessage.cs index 6ae0488fc2..da3690c93b 100644 --- a/OpenSim/Framework/GridInstantMessage.cs +++ b/OpenSim/Framework/GridInstantMessage.cs @@ -53,6 +53,24 @@ namespace OpenSim.Framework binaryBucket = new byte[0]; } + public GridInstantMessage(GridInstantMessage im, bool addTimestamp) + { + fromAgentID = im.fromAgentID; + fromAgentName = im.fromAgentName; + toAgentID = im.toAgentID; + dialog = im.dialog; + fromGroup = im.fromGroup; + message = im.message; + imSessionID = im.imSessionID; + offline = im.offline; + Position = im.Position; + binaryBucket = im.binaryBucket; + RegionID = im.RegionID; + + if (addTimestamp) + timestamp = (uint)Util.UnixTimeSinceEpoch(); + } + public GridInstantMessage(IScene scene, UUID _fromAgentID, string _fromAgentName, UUID _toAgentID, byte _dialog, bool _fromGroup, string _message, From 844ae7720e02d01b839986e0ba8fab93f9c93c05 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 7 Sep 2013 17:58:32 +0200 Subject: [PATCH 08/12] Bring Core Groups up to current version --- OpenSim/Addons/Groups/GroupsExtendedData.cs | 24 + .../Addons/Groups/GroupsMessagingModule.cs | 432 +++++++++++++----- OpenSim/Addons/Groups/GroupsModule.cs | 109 ++--- .../GroupsServiceHGConnectorModule.cs | 42 +- .../HGGroupsServiceRobustConnector.cs | 2 - .../Addons/Groups/IGroupsServicesConnector.cs | 6 - .../GroupsServiceLocalConnectorModule.cs | 22 - .../Remote/GroupsServiceRemoteConnector.cs | 31 ++ .../GroupsServiceRemoteConnectorModule.cs | 24 +- .../Remote/GroupsServiceRobustConnector.cs | 45 +- .../Groups/RemoteConnectorCacheWrapper.cs | 13 +- .../Addons/Groups/Service/GroupsService.cs | 40 +- 12 files changed, 505 insertions(+), 285 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsExtendedData.cs b/OpenSim/Addons/Groups/GroupsExtendedData.cs index 6f4db286f4..1632aee706 100644 --- a/OpenSim/Addons/Groups/GroupsExtendedData.cs +++ b/OpenSim/Addons/Groups/GroupsExtendedData.cs @@ -504,6 +504,30 @@ namespace OpenSim.Groups return notice; } + + public static Dictionary DirGroupsReplyData(DirGroupsReplyData g) + { + Dictionary dict = new Dictionary(); + + dict["GroupID"] = g.groupID; + dict["Name"] = g.groupName; + dict["NMembers"] = g.members; + dict["SearchOrder"] = g.searchOrder; + + return dict; + } + + public static DirGroupsReplyData DirGroupsReplyData(Dictionary dict) + { + DirGroupsReplyData g; + + g.groupID = new UUID(dict["GroupID"].ToString()); + g.groupName = dict["Name"].ToString(); + Int32.TryParse(dict["NMembers"].ToString(), out g.members); + float.TryParse(dict["SearchOrder"].ToString(), out g.searchOrder); + + return g; + } } } diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index d172d48c6c..be59c6258c 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -39,6 +39,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Groups { @@ -51,7 +52,7 @@ namespace OpenSim.Groups private IPresenceService m_presenceService; private IMessageTransferModule m_msgTransferModule = null; - + private IUserManagement m_UserManagement = null; private IGroupsServicesConnector m_groupData = null; // Config Options @@ -79,6 +80,10 @@ namespace OpenSim.Groups private int m_usersOnlineCacheExpirySeconds = 20; + private Dictionary> m_groupsAgentsDroppedFromChatSession = new Dictionary>(); + private Dictionary> m_groupsAgentsInvitedToChatSession = new Dictionary>(); + + #region Region Module interfaceBase Members public void Initialise(IConfigSource config) @@ -124,10 +129,12 @@ namespace OpenSim.Groups m_sceneList.Add(scene); scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; scene.EventManager.OnClientLogin += OnClientLogin; } - + public void RegionLoaded(Scene scene) { if (!m_groupMessagingEnabled) @@ -155,6 +162,17 @@ namespace OpenSim.Groups return; } + m_UserManagement = scene.RequestModuleInterface(); + + // No groups module, no groups messaging + if (m_UserManagement == null) + { + m_log.Error("[Groups.Messaging]: Could not get IUserManagement, GroupsMessagingModule is now disabled."); + RemoveRegion(scene); + return; + } + + if (m_presenceService == null) m_presenceService = scene.PresenceService; @@ -227,87 +245,107 @@ namespace OpenSim.Groups public void SendMessageToGroup(GridInstantMessage im, UUID groupID) { - List groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID).ToString(), groupID); + UUID fromAgentID = new UUID(im.fromAgentID); + List groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), groupID); int groupMembersCount = groupMembers.Count; + PresenceInfo[] onlineAgents = null; - if (m_messageOnlineAgentsOnly) + // In V2 we always only send to online members. + // Sending to offline members is not an option. + string[] t1 = groupMembers.ConvertAll(gmd => gmd.AgentID.ToString()).ToArray(); + + // We cache in order not to overwhlem the presence service on large grids with many groups. This does + // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed. + // (assuming this is the same across all grid simulators). + if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents)) { - string[] t1 = groupMembers.ConvertAll(gmd => gmd.AgentID.ToString()).ToArray(); + onlineAgents = m_presenceService.GetAgents(t1); + m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); + } - // We cache in order not to overwhlem the presence service on large grids with many groups. This does - // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed. - // (assuming this is the same across all grid simulators). - PresenceInfo[] onlineAgents; - if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents)) - { - onlineAgents = m_presenceService.GetAgents(t1); - m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); - } + HashSet onlineAgentsUuidSet = new HashSet(); + Array.ForEach(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); - HashSet onlineAgentsUuidSet = new HashSet(); - Array.ForEach(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); + groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); - groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); - - // if (m_debugEnabled) +// if (m_debugEnabled) // m_log.DebugFormat( // "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online", // groupID, groupMembersCount, groupMembers.Count()); - } - else - { - if (m_debugEnabled) - m_log.DebugFormat( - "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members", - groupID, groupMembers.Count); - } int requestStartTick = Environment.TickCount; + im.imSessionID = groupID.Guid; + im.fromGroup = true; + IClientAPI thisClient = GetActiveClient(fromAgentID); + if (thisClient != null) + { + im.RegionID = thisClient.Scene.RegionInfo.RegionID.Guid; + } + + // Send to self first of all + im.toAgentID = im.fromAgentID; + im.fromGroup = true; + ProcessMessageFromGroupSession(im); + + List regions = new List(); + List clientsAlreadySent = new List(); + + // Then send to everybody else foreach (GroupMembersData member in groupMembers) { - if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) + if (member.AgentID.Guid == im.fromAgentID) + continue; + + if (clientsAlreadySent.Contains(member.AgentID)) + continue; + clientsAlreadySent.Add(member.AgentID); + + if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) { // Don't deliver messages to people who have dropped this session if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID); continue; } - // Copy Message - GridInstantMessage msg = new GridInstantMessage(); - msg.imSessionID = groupID.Guid; - msg.fromAgentName = im.fromAgentName; - msg.message = im.message; - msg.dialog = im.dialog; - msg.offline = im.offline; - msg.ParentEstateID = im.ParentEstateID; - msg.Position = im.Position; - msg.RegionID = im.RegionID; - msg.binaryBucket = im.binaryBucket; - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - - msg.fromAgentID = im.fromAgentID; - msg.fromGroup = true; - - msg.toAgentID = member.AgentID.Guid; + im.toAgentID = member.AgentID.Guid; IClientAPI client = GetActiveClient(member.AgentID); if (client == null) { // If they're not local, forward across the grid + // BUT do it only once per region, please! Sim would be even better! if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} via Grid", member.AgentID); - m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); + + bool reallySend = true; + if (onlineAgents != null) + { + PresenceInfo presence = onlineAgents.First(p => p.UserID == member.AgentID.ToString()); + if (regions.Contains(presence.RegionID)) + reallySend = false; + else + regions.Add(presence.RegionID); + } + + if (reallySend) + { + // We have to create a new IM structure because the transfer module + // uses async send + GridInstantMessage msg = new GridInstantMessage(im, true); + m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); + } } else { // Deliver locally, directly if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); - ProcessMessageFromGroupSession(msg); + + ProcessMessageFromGroupSession(im); } + } - // Temporary for assessing how long it still takes to send messages to large online groups. - if (m_messageOnlineAgentsOnly) + if (m_debugEnabled) m_log.DebugFormat( "[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); @@ -324,9 +362,20 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name); - client.OnInstantMessage += OnInstantMessage; + ResetAgentGroupChatSessions(client.AgentId.ToString()); } + void OnMakeRootAgent(ScenePresence sp) + { + sp.ControllingClient.OnInstantMessage += OnInstantMessage; + } + + void OnMakeChildAgent(ScenePresence sp) + { + sp.ControllingClient.OnInstantMessage -= OnInstantMessage; + } + + private void OnGridInstantMessage(GridInstantMessage msg) { // The instant message module will only deliver messages of dialog types: @@ -335,21 +384,91 @@ namespace OpenSim.Groups // Any other message type will not be delivered to a client by the // Instant Message Module - + UUID regionID = new UUID(msg.RegionID); if (m_debugEnabled) { - m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}", + System.Reflection.MethodBase.GetCurrentMethod().Name, regionID); DebugGridInstantMessage(msg); } // Incoming message from a group - if ((msg.fromGroup == true) && - ((msg.dialog == (byte)InstantMessageDialog.SessionSend) - || (msg.dialog == (byte)InstantMessageDialog.SessionAdd) - || (msg.dialog == (byte)InstantMessageDialog.SessionDrop))) + if ((msg.fromGroup == true) && (msg.dialog == (byte)InstantMessageDialog.SessionSend)) { - ProcessMessageFromGroupSession(msg); + // We have to redistribute the message across all members of the group who are here + // on this sim + + UUID GroupID = new UUID(msg.imSessionID); + + Scene aScene = m_sceneList[0]; + GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); + + List groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), GroupID); + + //if (m_debugEnabled) + // foreach (GroupMembersData m in groupMembers) + // m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID); + + foreach (Scene s in m_sceneList) + { + s.ForEachScenePresence(sp => + { + // If we got this via grid messaging, it's because the caller thinks + // that the root agent is here. We should only send the IM to root agents. + if (sp.IsChildAgent) + return; + + GroupMembersData m = groupMembers.Find(gmd => + { + return gmd.AgentID == sp.UUID; + }); + if (m.AgentID == UUID.Zero) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he is not a member of the group", sp.UUID); + return; + } + + // Check if the user has an agent in the region where + // the IM came from, and if so, skip it, because the IM + // was already sent via that agent + if (regionOfOrigin != null) + { + AgentCircuitData aCircuit = s.AuthenticateHandler.GetAgentCircuitData(sp.UUID); + if (aCircuit != null) + { + if (aCircuit.ChildrenCapSeeds.Keys.Contains(regionOfOrigin.RegionHandle)) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he has an agent in region of origin", sp.UUID); + return; + } + else + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: not skipping agent {0}", sp.UUID); + } + } + } + + UUID AgentID = sp.UUID; + msg.toAgentID = AgentID.Guid; + + if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)) + { + if (!hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)) + AddAgentToSession(AgentID, GroupID, msg); + else + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name); + + ProcessMessageFromGroupSession(msg); + } + } + }); + + } } } @@ -359,82 +478,40 @@ namespace OpenSim.Groups UUID AgentID = new UUID(msg.fromAgentID); UUID GroupID = new UUID(msg.imSessionID); + UUID toAgentID = new UUID(msg.toAgentID); switch (msg.dialog) { case (byte)InstantMessageDialog.SessionAdd: - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); break; case (byte)InstantMessageDialog.SessionDrop: - m_groupData.AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID); + AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID); break; case (byte)InstantMessageDialog.SessionSend: - if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID) - && !m_groupData.hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID) - ) + // User hasn't dropped, so they're in the session, + // maybe we should deliver it. + IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); + if (client != null) { - // Agent not in session and hasn't dropped from session - // Add them to the session for now, and Invite them - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + // Deliver locally, directly + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name); - UUID toAgentID = new UUID(msg.toAgentID); - IClientAPI activeClient = GetActiveClient(toAgentID); - if (activeClient != null) + if (!hasAgentDroppedGroupChatSession(toAgentID.ToString(), GroupID)) { - GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); - if (groupInfo != null) - { - if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message"); - - // Force? open the group session dialog??? - // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); - IEventQueue eq = activeClient.Scene.RequestModuleInterface(); - eq.ChatterboxInvitation( - GroupID - , groupInfo.GroupName - , new UUID(msg.fromAgentID) - , msg.message - , new UUID(msg.toAgentID) - , msg.fromAgentName - , msg.dialog - , msg.timestamp - , msg.offline == 1 - , (int)msg.ParentEstateID - , msg.Position - , 1 - , new UUID(msg.imSessionID) - , msg.fromGroup - , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName) - ); - - eq.ChatterBoxSessionAgentListUpdates( - new UUID(GroupID) - , new UUID(msg.fromAgentID) - , new UUID(msg.toAgentID) - , false //canVoiceChat - , false //isModerator - , false //text mute - ); - } + if (!hasAgentBeenInvitedToGroupChatSession(toAgentID.ToString(), GroupID)) + // This actually sends the message too, so no need to resend it + // with client.SendInstantMessage + AddAgentToSession(toAgentID, GroupID, msg); + else + client.SendInstantMessage(msg); } } - else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)) + else { - // User hasn't dropped, so they're in the session, - // maybe we should deliver it. - IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); - if (client != null) - { - // Deliver locally, directly - if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name); - client.SendInstantMessage(msg); - } - else - { - m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); - } + m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); } break; @@ -444,6 +521,53 @@ namespace OpenSim.Groups } } + private void AddAgentToSession(UUID AgentID, UUID GroupID, GridInstantMessage msg) + { + // Agent not in session and hasn't dropped from session + // Add them to the session for now, and Invite them + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + + IClientAPI activeClient = GetActiveClient(AgentID); + if (activeClient != null) + { + GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); + if (groupInfo != null) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message"); + + // Force? open the group session dialog??? + // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); + IEventQueue eq = activeClient.Scene.RequestModuleInterface(); + eq.ChatterboxInvitation( + GroupID + , groupInfo.GroupName + , new UUID(msg.fromAgentID) + , msg.message + , AgentID + , msg.fromAgentName + , msg.dialog + , msg.timestamp + , msg.offline == 1 + , (int)msg.ParentEstateID + , msg.Position + , 1 + , new UUID(msg.imSessionID) + , msg.fromGroup + , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName) + ); + + eq.ChatterBoxSessionAgentListUpdates( + new UUID(GroupID) + , AgentID + , new UUID(msg.toAgentID) + , false //canVoiceChat + , false //isModerator + , false //text mute + ); + } + } + } + #endregion @@ -469,7 +593,7 @@ namespace OpenSim.Groups if (groupInfo != null) { - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID); @@ -495,7 +619,7 @@ namespace OpenSim.Groups m_log.DebugFormat("[Groups.Messaging]: Send message to session for group {0} with session ID {1}", GroupID, im.imSessionID.ToString()); //If this agent is sending a message, then they want to be in the session - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); SendMessageToGroup(im, GroupID); } @@ -566,12 +690,12 @@ namespace OpenSim.Groups { if (!sp.IsChildAgent) { - if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name); + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name); return sp.ControllingClient; } else { - if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name); + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name); child = sp.ControllingClient; } } @@ -590,5 +714,71 @@ namespace OpenSim.Groups } #endregion + + #region GroupSessionTracking + + public void ResetAgentGroupChatSessions(string agentID) + { + foreach (List agentList in m_groupsAgentsDroppedFromChatSession.Values) + agentList.Remove(agentID); + + foreach (List agentList in m_groupsAgentsInvitedToChatSession.Values) + agentList.Remove(agentID); + } + + public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) + { + // If we're tracking this group, and we can find them in the tracking, then they've been invited + return m_groupsAgentsInvitedToChatSession.ContainsKey(groupID) + && m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID); + } + + public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) + { + // If we're tracking drops for this group, + // and we find them, well... then they've dropped + return m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID) + && m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID); + } + + public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) + { + if (m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) + { + // If not in dropped list, add + if (!m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) + { + m_groupsAgentsDroppedFromChatSession[groupID].Add(agentID); + } + } + } + + public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) + { + // Add Session Status if it doesn't exist for this session + CreateGroupChatSessionTracking(groupID); + + // If nessesary, remove from dropped list + if (m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) + { + m_groupsAgentsDroppedFromChatSession[groupID].Remove(agentID); + } + + // Add to invited + if (!m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID)) + m_groupsAgentsInvitedToChatSession[groupID].Add(agentID); + } + + private void CreateGroupChatSessionTracking(UUID groupID) + { + if (!m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) + { + m_groupsAgentsDroppedFromChatSession.Add(groupID, new List()); + m_groupsAgentsInvitedToChatSession.Add(groupID, new List()); + } + + } + #endregion + } } diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index f805d69f58..b0493faaf5 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -141,6 +141,8 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRoot; + scene.EventManager.OnMakeChildAgent += OnMakeChild; scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; // The InstantMessageModule itself doesn't do this, // so lets see if things explode if we don't do it @@ -194,6 +196,8 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnMakeRootAgent -= OnMakeRoot; + scene.EventManager.OnMakeChildAgent -= OnMakeChild; scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; lock (m_sceneList) @@ -232,16 +236,29 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); - client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; - client.OnDirFindQuery += OnDirFindQuery; client.OnRequestAvatarProperties += OnRequestAvatarProperties; + } + private void OnMakeRoot(ScenePresence sp) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + sp.ControllingClient.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; // Used for Notices and Group Invites/Accept/Reject - client.OnInstantMessage += OnInstantMessage; + sp.ControllingClient.OnInstantMessage += OnInstantMessage; // Send client their groups information. - SendAgentGroupDataUpdate(client, client.AgentId); + SendAgentGroupDataUpdate(sp.ControllingClient, sp.UUID); + } + + private void OnMakeChild(ScenePresence sp) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + sp.ControllingClient.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest; + // Used for Notices and Group Invites/Accept/Reject + sp.ControllingClient.OnInstantMessage -= OnInstantMessage; } private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) @@ -287,21 +304,6 @@ namespace OpenSim.Groups } */ - void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) - { - if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups) - { - if (m_debugEnabled) - m_log.DebugFormat( - "[Groups]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})", - System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart); - - // TODO: This currently ignores pretty much all the query flags including Mature and sort order - remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), queryText).ToArray()); - } - - } - private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -347,7 +349,7 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); - m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog); + //m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog); // Group invitations if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)) { @@ -465,12 +467,12 @@ namespace OpenSim.Groups } // Send notice out to everyone that wants notices - // Build notice IIM - GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID)) { if (member.AcceptNotices) { + // Build notice IIM, one of reach, because the sending may be async + GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); msg.toAgentID = member.AgentID.Guid; OutgoingInstantMessage(msg, member.AgentID); } @@ -485,7 +487,7 @@ namespace OpenSim.Groups return; //// 16 bytes are the UUID. Maybe. - UUID folderID = new UUID(im.binaryBucket, 0); +// UUID folderID = new UUID(im.binaryBucket, 0); UUID noticeID = new UUID(im.imSessionID); GroupNoticeInfo notice = m_groupData.GetGroupNotice(remoteClient.AgentId.ToString(), noticeID); @@ -766,14 +768,17 @@ namespace OpenSim.Groups remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group."); return UUID.Zero; } - money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate); } + string reason = string.Empty; UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, remoteClient.AgentId, out reason); if (groupID != UUID.Zero) { + if (money != null) + money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate); + remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly"); // Update the founder with new group information. @@ -904,23 +909,7 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called for notice {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupNoticeID); - //GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null); - GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested); - //GridInstantMessage msg = new GridInstantMessage(); - //msg.imSessionID = UUID.Zero.Guid; - //msg.fromAgentID = data.GroupID.Guid; - //msg.toAgentID = GetRequestingAgentID(remoteClient).Guid; - //msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - //msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName; - //msg.message = data.noticeData.Subject + "|" + data.Message; - //msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested; - //msg.fromGroup = true; - //msg.offline = (byte)0; - //msg.ParentEstateID = 0; - //msg.Position = Vector3.Zero; - //msg.RegionID = UUID.Zero.Guid; - //msg.binaryBucket = data.BinaryBucket; OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient)); } @@ -1002,6 +991,10 @@ namespace OpenSim.Groups // Should this send updates to everyone in the group? SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + + if (reason != string.Empty) + // A warning + remoteClient.SendAlertMessage("Warning: " + reason); } else remoteClient.SendJoinGroupReply(groupID, false); @@ -1186,6 +1179,11 @@ namespace OpenSim.Groups } } + public List FindGroups(IClientAPI remoteClient, string query) + { + return m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), query); + } + #endregion #region Client/Update Tools @@ -1225,12 +1223,16 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + // NPCs currently don't have a CAPs structure or event queues. There is a strong argument for conveying this information + // to them anyway since it makes writing server-side bots a lot easier, but for now we don't do anything. + if (remoteClient.SceneAgent.PresenceType == PresenceType.Npc) + return; + OSDArray AgentData = new OSDArray(1); OSDMap AgentDataMap = new OSDMap(1); AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID)); AgentData.Add(AgentDataMap); - OSDArray GroupData = new OSDArray(data.Length); OSDArray NewGroupData = new OSDArray(data.Length); @@ -1276,8 +1278,7 @@ namespace OpenSim.Groups if (queue != null) { queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient)); - } - + } } private void SendScenePresenceUpdate(UUID AgentID, string Title) @@ -1339,6 +1340,7 @@ namespace OpenSim.Groups GroupMembershipData[] membershipArray = GetProfileListedGroupMemberships(remoteClient, dataForAgentID); SendGroupMembershipInfoViaCaps(remoteClient, dataForAgentID, membershipArray); + //remoteClient.SendAvatarGroupsReply(dataForAgentID, membershipArray); if (remoteClient.AgentId == dataForAgentID) remoteClient.RefreshGroupMembership(); @@ -1399,19 +1401,18 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff - UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, dataForAgentID); - string firstname, lastname; - if (account != null) + string firstname = "Unknown", lastname = "Unknown"; + string name = m_UserManagement.GetUserName(dataForAgentID); + if (!string.IsNullOrEmpty(name)) { - firstname = account.FirstName; - lastname = account.LastName; + string[] parts = name.Split(new char[] { ' ' }); + if (parts.Length >= 2) + { + firstname = parts[0]; + lastname = parts[1]; + } } - else - { - firstname = "Unknown"; - lastname = "Unknown"; - } - + remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname, lastname, activeGroupPowers, activeGroupName, activeGroupTitle); diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index f670272662..4642b2adaf 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -186,7 +186,6 @@ namespace OpenSim.Groups public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason) { - m_log.DebugFormat("[Groups]: Creating group {0}", name); reason = string.Empty; if (m_UserManagement.IsLocalGridUser(RequestingAgentID)) return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID, @@ -255,7 +254,10 @@ namespace OpenSim.Groups { string url = string.Empty, gname = string.Empty; if (IsLocal(GroupID, out url, out gname)) - return m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), GroupID); + { + string agentID = AgentUUI(RequestingAgentID); + return m_LocalGroupsConnector.GetGroupMembers(agentID, GroupID); + } else if (!string.IsNullOrEmpty(url)) { ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID); @@ -397,17 +399,21 @@ namespace OpenSim.Groups if (success) { + // Here we always return true. The user has been added to the local group, + // independent of whether the remote operation succeeds or not url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI"); if (url == string.Empty) { - reason = "User doesn't have a groups server"; - return false; + reason = "You don't have an accessible groups server in your home world. You membership to this group in only within this grid."; + return true; } GroupsServiceHGConnector c = GetConnector(url); if (c != null) - return c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason); + c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason); + return true; } + return false; } } else if (m_UserManagement.IsLocalGridUser(uid)) // local user @@ -544,7 +550,6 @@ namespace OpenSim.Groups List urls = new List(); foreach (GroupMembersData m in members) { - UUID userID = UUID.Zero; if (!m_UserManagement.IsLocalGridUser(m.AgentID)) { string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI"); @@ -592,28 +597,6 @@ namespace OpenSim.Groups return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID); } - public void ResetAgentGroupChatSessions(string agentID) - { - } - - public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) - { - } - - public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) - { - } - #endregion #region hypergrid groups @@ -685,6 +668,9 @@ namespace OpenSim.Groups { serviceLocation = string.Empty; name = string.Empty; + if (groupID.Equals(UUID.Zero)) + return true; + ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty); if (group == null) { diff --git a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs index 3584f78c52..6f589226f2 100644 --- a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs @@ -47,7 +47,6 @@ namespace OpenSim.Groups private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private HGGroupsService m_GroupsService; - private string m_HomeURI = string.Empty; private string m_ConfigName = "Groups"; // Called by Robust shell @@ -209,7 +208,6 @@ namespace OpenSim.Groups UUID groupID = new UUID(request["GroupID"].ToString()); string agentID = request["AgentID"].ToString(); string token = request["AccessToken"].ToString(); - string reason = string.Empty; m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token); } diff --git a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs index 73deb7a7b4..a09b59e238 100644 --- a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs +++ b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs @@ -92,12 +92,6 @@ namespace OpenSim.Groups GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID); List GetGroupNotices(string RequestingAgentID, UUID GroupID); - void ResetAgentGroupChatSessions(string agentID); - bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID); - bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID); - void AgentDroppedFromGroupChatSession(string agentID, UUID groupID); - void AgentInvitedToGroupChatSession(string agentID, UUID groupID); - } public class GroupInviteInfo diff --git a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs index 905bc913ff..564dec4543 100644 --- a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs +++ b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs @@ -320,28 +320,6 @@ namespace OpenSim.Groups return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID); } - public void ResetAgentGroupChatSessions(string agentID) - { - } - - public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) - { - } - - public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) - { - } - #endregion } } diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs index 04328c9c3a..161ca0c4cc 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs @@ -133,6 +133,36 @@ namespace OpenSim.Groups return GroupsDataUtils.GroupRecord((Dictionary)ret["RESULT"]); } + public List FindGroups(string RequestingAgentID, string query) + { + List hits = new List(); + if (string.IsNullOrEmpty(query)) + return hits; + + Dictionary sendData = new Dictionary(); + sendData["Query"] = query; + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("FINDGROUPS", sendData); + + if (ret == null) + return hits; + + if (!ret.ContainsKey("RESULT")) + return hits; + + if (ret["RESULT"].ToString() == "NULL") + return hits; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + DirGroupsReplyData m = GroupsDataUtils.DirGroupsReplyData((Dictionary)v); + hits.Add(m); + } + + return hits; + } + public GroupMembershipData AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) { reason = string.Empty; @@ -226,6 +256,7 @@ namespace OpenSim.Groups Dictionary sendData = new Dictionary(); sendData["GroupID"] = GroupID.ToString(); sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETGROUPMEMBERS", sendData); if (ret == null) diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs index f1cf66c5ba..d3de0e8975 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs @@ -199,7 +199,7 @@ namespace OpenSim.Groups public List FindGroups(string RequestingAgentID, string search) { // TODO! - return new List(); + return m_GroupsService.FindGroups(RequestingAgentID, search); } public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) @@ -406,28 +406,6 @@ namespace OpenSim.Groups }); } - public void ResetAgentGroupChatSessions(string agentID) - { - } - - public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) - { - } - - public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) - { - } - #endregion } diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index f991d016f0..7e55d3ce8a 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -133,6 +133,8 @@ namespace OpenSim.Groups return HandleAddNotice(request); case "GETNOTICES": return HandleGetNotices(request); + case "FINDGROUPS": + return HandleFindGroups(request); } m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method); } @@ -170,11 +172,16 @@ namespace OpenSim.Groups } - grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID); - if (grec == null) - NullResult(result, "Internal Error"); + if (grec.GroupID != UUID.Zero) + { + grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID); + if (grec == null) + NullResult(result, "Internal Error"); + else + result["RESULT"] = GroupsDataUtils.GroupRecord(grec); + } else - result["RESULT"] = GroupsDataUtils.GroupRecord(grec); + NullResult(result, reason); } string xmlString = ServerUtils.BuildXmlResponse(result); @@ -264,7 +271,6 @@ namespace OpenSim.Groups UUID groupID = new UUID(request["GroupID"].ToString()); string agentID = request["AgentID"].ToString(); string requestingAgentID = request["RequestingAgentID"].ToString(); - string reason = string.Empty; m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID); } @@ -495,7 +501,6 @@ namespace OpenSim.Groups else { string op = request["OP"].ToString(); - string reason = string.Empty; bool success = false; if (op == "ADD") @@ -563,7 +568,6 @@ namespace OpenSim.Groups else { string op = request["OP"].ToString(); - string reason = string.Empty; if (op == "GROUP") { @@ -626,7 +630,6 @@ namespace OpenSim.Groups else { string op = request["OP"].ToString(); - string reason = string.Empty; if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID")) { @@ -739,6 +742,32 @@ namespace OpenSim.Groups return Util.UTF8NoBomEncoding.GetBytes(xmlString); } + byte[] HandleFindGroups(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("Query")) + NullResult(result, "Bad network data"); + + List hits = m_GroupsService.FindGroups(request["RequestingAgentID"].ToString(), request["Query"].ToString()); + + if (hits == null || (hits != null && hits.Count == 0)) + NullResult(result, "No hits"); + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (DirGroupsReplyData n in hits) + dict["n-" + i++] = GroupsDataUtils.DirGroupsReplyData(n); + + result["RESULT"] = dict; + } + + + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + #region Helpers diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs index e7d38c2020..3ac74fceb2 100644 --- a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs +++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs @@ -53,7 +53,7 @@ namespace OpenSim.Groups private ForeignImporter m_ForeignImporter; private Dictionary m_ActiveRequests = new Dictionary(); - private const int GROUPS_CACHE_TIMEOUT = 5 * 60; // 5 minutes + private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes // This all important cache cahces objects of different types: // group- or group- => ExtendedGroupRecord @@ -209,13 +209,10 @@ namespace OpenSim.Groups public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d) { GroupMembershipData activeGroup = d(); - if (activeGroup != null) - { - string cacheKey = "active-" + AgentID.ToString(); - lock (m_Cache) - if (m_Cache.Contains(cacheKey)) - m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); - } + string cacheKey = "active-" + AgentID.ToString(); + lock (m_Cache) + if (m_Cache.Contains(cacheKey)) + m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); } public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d) diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index 0668870ef1..037ef59b9e 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -130,6 +130,13 @@ namespace OpenSim.Groups { reason = string.Empty; + // Check if the group already exists + if (m_Database.RetrieveGroup(name) != null) + { + reason = "A group with that name already exists"; + return UUID.Zero; + } + // Create the group GroupData data = new GroupData(); data.GroupID = UUID.Random(); @@ -248,13 +255,20 @@ namespace OpenSim.Groups return members; List rolesList = new List(roles); - // Is the requester a member of the group? - bool isInGroup = false; - if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null) - isInGroup = true; + // Check visibility? + // When we don't want to check visibility, we pass it "all" as the requestingAgentID + bool checkVisibility = !RequestingAgentID.Equals(UUID.Zero.ToString()); - if (!isInGroup) // reduce the roles to the visible ones - rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0); + if (checkVisibility) + { + // Is the requester a member of the group? + bool isInGroup = false; + if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null) + isInGroup = true; + + if (!isInGroup) // reduce the roles to the visible ones + rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0); + } MembershipData[] datas = m_Database.RetrieveMembers(GroupID); if (datas == null || (datas != null && datas.Length == 0)) @@ -723,12 +737,12 @@ namespace OpenSim.Groups #region Actions without permission checks - private void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) { _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty); } - public void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + protected void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) { // 1. Delete membership m_Database.DeleteMember(GroupID, AgentID); @@ -780,7 +794,7 @@ namespace OpenSim.Groups } - private bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add) + protected bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add) { RoleData data = m_Database.RetrieveRole(groupID, roleID); @@ -810,12 +824,12 @@ namespace OpenSim.Groups return m_Database.StoreRole(data); } - private void _RemoveGroupRole(UUID groupID, UUID roleID) + protected void _RemoveGroupRole(UUID groupID, UUID roleID) { m_Database.DeleteRole(groupID, roleID); } - private void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + protected void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) { RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); if (data != null) @@ -840,7 +854,7 @@ namespace OpenSim.Groups } - private List _GetGroupRoles(UUID groupID) + protected List _GetGroupRoles(UUID groupID) { List roles = new List(); @@ -865,7 +879,7 @@ namespace OpenSim.Groups return roles; } - private List _GetGroupRoleMembers(UUID GroupID, bool isInGroup) + protected List _GetGroupRoleMembers(UUID GroupID, bool isInGroup) { List rmembers = new List(); From 59290854f24f47ee7cb8b2a242e3f771fa30229b Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sun, 8 Sep 2013 17:53:21 +0200 Subject: [PATCH 09/12] Reinstate SecurePermissionsLoading functionality, default ON --- OpenSim/Region/Application/OpenSimBase.cs | 40 +++++++++-------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 7361f50ac6..25af9ac950 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -195,7 +195,9 @@ namespace OpenSim m_securePermissionsLoading = startupConfig.GetBoolean("SecurePermissionsLoading", true); - string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule"); + string permissionModules = Util.GetConfigVarFromSections(Config, "permissionmodules", + new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule"); + m_permsModules = new List(permissionModules.Split(',')); } @@ -392,29 +394,19 @@ namespace OpenSim } else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing..."); - // XPTO: Fix this -// if (m_securePermissionsLoading) -// { -// foreach (string s in m_permsModules) -// { -// if (!scene.RegionModules.ContainsKey(s)) -// { -// bool found = false; -// foreach (IRegionModule m in modules) -// { -// if (m.Name == s) -// { -// found = true; -// } -// } -// if (!found) -// { -// m_log.Fatal("[MODULES]: Required module " + s + " not found."); -// Environment.Exit(0); -// } -// } -// } -// } + if (m_securePermissionsLoading) + { + foreach (string s in m_permsModules) + { + if (!scene.RegionModules.ContainsKey(s)) + { + m_log.Fatal("[MODULES]: Required module " + s + " not found."); + Environment.Exit(0); + } + } + + m_log.InfoFormat("[SCENE]: Secure permissions loading enabled, modules loaded: {0}", String.Join(" ", m_permsModules)); + } scene.SetModuleInterfaces(); // First Step of bootreport sequence From b41ae0f98f85db76b9a412cee29e9bcba5b4d9d9 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sun, 8 Sep 2013 17:54:00 +0200 Subject: [PATCH 10/12] Harmonize the class name, ID and Name of the default perms module --- .../CoreModules/World/Permissions/PermissionsModule.cs | 6 +++--- .../Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs | 6 +++--- .../Framework/Scenes/Tests/SceneObjectUserGroupTests.cs | 4 ++-- .../Framework/Scenes/Tests/ScenePresenceTeleportTests.cs | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 79dd4a09d2..26e9131627 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -42,8 +42,8 @@ using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Region.CoreModules.World.Permissions { - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PermissionsModule")] - public class PermissionsModule : INonSharedRegionModule, IPermissionsModule + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DefaultPermissionsModule")] + public class DefaultPermissionsModule : INonSharedRegionModule, IPermissionsModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -348,7 +348,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions public string Name { - get { return "PermissionsModule"; } + get { return "DefaultPermissionsModule"; } } public Type ReplaceableInterface diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 52ad5380e3..9557cd0ed2 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs @@ -67,7 +67,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Startup"); config.Set("serverside_object_permissions", true); - SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); + SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new DefaultPermissionsModule() }); IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. @@ -112,7 +112,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Startup"); config.Set("serverside_object_permissions", true); - SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); + SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new DefaultPermissionsModule() }); IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. @@ -195,4 +195,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Assert.That(retrievedPart, Is.Null); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs index c7eaff9d00..e7a1fe0bdc 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs @@ -71,7 +71,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneHelpers.SetupSceneModules( scene, configSource, new object[] - { new PermissionsModule(), + { new DefaultPermissionsModule(), new GroupsModule(), new MockGroupsServicesConnector() }); @@ -82,4 +82,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests groupsModule.CreateGroup(client, "group1", "To boldly go", true, UUID.Zero, 5, true, true, true); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index de4458dde3..8d94d29629 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -216,7 +216,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // We need to set up the permisions module on scene B so that our later use of agent limit to deny // QueryAccess won't succeed anyway because administrators are always allowed in and the default // IsAdministrator if no permissions module is present is true. - SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB }); + SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new DefaultPermissionsModule(), etmB }); // Shared scene modules SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); @@ -381,7 +381,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // We need to set up the permisions module on scene B so that our later use of agent limit to deny // QueryAccess won't succeed anyway because administrators are always allowed in and the default // IsAdministrator if no permissions module is present is true. - SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB }); + SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new DefaultPermissionsModule(), etmB }); // Shared scene modules SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); @@ -507,4 +507,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests // TestHelpers.DisableLogging(); } } -} \ No newline at end of file +} From 528fc5358df93ae7a6f9e32f696550d21ef3d08c Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sun, 8 Sep 2013 18:23:06 +0200 Subject: [PATCH 11/12] Fix exception when brokering HG asset ids --- .../Services/Connectors/Asset/AssetServicesConnector.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 4b502b7ff2..8b702e0b8c 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -137,7 +137,13 @@ namespace OpenSim.Services.Connectors string prefix = id.Substring(0, 2).ToLower(); - string host = m_UriMap[prefix]; + string host; + + // HG URLs will not be valid UUIDS + if (m_UriMap.ContainsKey(prefix)) + host = m_UriMap[prefix]; + else + host = m_UriMap["00"]; serverUri.Host = host; From ddf67bf929fbc32d8319f777b248642b4da0305a Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Sep 2013 19:41:51 +0200 Subject: [PATCH 12/12] Mono 2.0 fix - call ToArray() explicitly --- OpenSim/Region/Application/OpenSimBase.cs | 2 +- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 12 ++++++++++++ OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 1 + OpenSim/Region/Framework/Scenes/ScenePresence.cs | 9 +++++---- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 25af9ac950..88bd869054 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -405,7 +405,7 @@ namespace OpenSim } } - m_log.InfoFormat("[SCENE]: Secure permissions loading enabled, modules loaded: {0}", String.Join(" ", m_permsModules)); + m_log.InfoFormat("[SCENE]: Secure permissions loading enabled, modules loaded: {0}", String.Join(" ", m_permsModules.ToArray())); } scene.SetModuleInterfaces(); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index eebb8aef8c..f4ea975f60 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -3933,6 +3933,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP part.Shape.ProfileHollow = 27500; } } + else if (update.Entity is ScenePresence) + { + ScenePresence presence = (ScenePresence)update.Entity; + + // If ParentUUID is not UUID.Zero and ParentID is 0, this + // avatar is in the process of crossing regions while + // sat on an object. In this state, we don't want any + // updates because they will visually orbit the avatar. + // Update will be forced once crossing is completed anyway. + if (presence.ParentUUID != UUID.Zero && presence.ParentID == 0) + continue; + } ++updatesThisCall; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index f306651b1b..3e1dcaad49 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -591,6 +591,7 @@ namespace OpenSim.Region.Framework.Scenes avinfo.ParentID = av.ParentID; avsToCross.Add(avinfo); + av.PrevSitOffset = av.OffsetPosition; av.ParentID = 0; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 0ab267a4d0..7004d23617 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -242,7 +242,7 @@ namespace OpenSim.Region.Framework.Scenes private int m_movementAnimationUpdateCounter = 0; - private Vector3 m_prevSitOffset; + public Vector3 PrevSitOffset { get; set; } protected AvatarAppearance m_appearance; @@ -957,7 +957,7 @@ namespace OpenSim.Region.Framework.Scenes // ParentPosition = part.GetWorldPosition(); ParentID = part.LocalId; ParentPart = part; - m_pos = m_prevSitOffset; + m_pos = PrevSitOffset; // pos = ParentPosition; pos = part.GetWorldPosition(); } @@ -2261,6 +2261,7 @@ namespace OpenSim.Region.Framework.Scenes if (ParentID != 0) { + PrevSitOffset = m_pos; // Save sit offset SceneObjectPart part = ParentPart; UnRegisterSeatControls(part.ParentGroup.UUID); @@ -3487,7 +3488,7 @@ namespace OpenSim.Region.Framework.Scenes cAgent.Appearance = new AvatarAppearance(Appearance); cAgent.ParentPart = ParentUUID; - cAgent.SitOffset = m_pos; + cAgent.SitOffset = PrevSitOffset; lock (scriptedcontrols) { @@ -3530,7 +3531,7 @@ namespace OpenSim.Region.Framework.Scenes CameraLeftAxis = cAgent.LeftAxis; CameraUpAxis = cAgent.UpAxis; ParentUUID = cAgent.ParentPart; - m_prevSitOffset = cAgent.SitOffset; + PrevSitOffset = cAgent.SitOffset; // When we get to the point of re-computing neighbors everytime this // changes, then start using the agent's drawdistance rather than the