From b6076d7b337dc087807e56cdbe74ef47dc1b66b3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 8 Jun 2010 15:07:57 +0100 Subject: [PATCH 1/4] Reduce number of full updates sent on region crossing for attachments/huds to 1 from 3 This is one step towards reducing hud glitches on region crossing, since the viewer fails to display prims if it receives child full updates before the root prim full update This commit also introduces a mechanism in LLClientView to stop child attachment updates ever going out before the root one This is a very temporary mechanism and will be commented out when the next step of the fix (to give root prims higher udpate priority) is committed This code is a foreport from the equivalent changes in 0.6.9-post-fixes --- .../ClientStack/LindenUDP/LLClientView.cs | 43 ++++++++++++++++++- OpenSim/Region/Framework/Scenes/Scene.cs | 42 +++++++++++++++--- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 10 +++-- .../Framework/Scenes/SceneObjectGroup.cs | 3 +- 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index a516a54ca4..0e58986932 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -331,6 +331,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// protected HashSet m_killRecord; + protected HashSet m_attachmentsSent; + private int m_moneyBalance; private int m_animationSequenceNumber = 1; private bool m_SendLogoutPacketWhenClosing = true; @@ -427,6 +429,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new HashSet(); + m_attachmentsSent = new HashSet(); m_assetService = m_scene.RequestModuleInterface(); m_hyperAssets = m_scene.RequestModuleInterface(); @@ -3411,6 +3414,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); OutPacket(objupdate, ThrottleOutPacketType.Task); + + // We need to record the avatar local id since the root prim of an attachment points to this. + m_attachmentsSent.Add(avatar.LocalId); } public void SendCoarseLocationUpdate(List users, List CoarseLocations) @@ -3466,7 +3472,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP double priority = m_prioritizer.GetUpdatePriority(this, entity); lock (m_entityUpdates.SyncRoot) - m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags), entity.LocalId); + m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags), entity.LocalId); } private void ProcessEntityUpdates(int maxUpdates) @@ -3542,9 +3548,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!canUseImproved && !canUseCompressed) { if (update.Entity is ScenePresence) + { objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); + } else - objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); + { + if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + string text = sop.Text; + if (text.IndexOf("\n") >= 0) + text = text.Remove(text.IndexOf("\n")); + + if (m_attachmentsSent.Contains(sop.ParentID)) + { +// m_log.DebugFormat( +// "[CLIENT]: Sending full info about attached prim {0} text {1}", +// sop.LocalId, text); + + objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); + + m_attachmentsSent.Add(sop.LocalId); + } + else + { + m_log.DebugFormat( + "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", + sop.LocalId, text, sop.ParentID); + + m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); + } + } + else + { + objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); + } + } } else if (!canUseImproved) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 2544359570..4e90d09649 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2066,8 +2066,34 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.ScheduleGroupForFullUpdate(); return sceneObject; + } + + /// + /// Add an object into the scene that has come from storage + /// + /// + /// + /// + /// If true, changes to the object will be reflected in its persisted data + /// If false, the persisted data will not be changed even if the object in the scene is changed + /// + /// + /// If true, we won't persist this object until it changes + /// If false, we'll persist this object immediately + /// + /// + /// If true, we send updates to the client to tell it about this object + /// If false, we leave it up to the caller to do this + /// + /// + /// true if the object was added, false if an object with the same uuid was already in the scene + /// + public bool AddRestoredSceneObject( + SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) + { + return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); } - + /// /// Add an object into the scene that has come from storage /// @@ -2087,7 +2113,7 @@ namespace OpenSim.Region.Framework.Scenes public bool AddRestoredSceneObject( SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted) { - return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted); + return AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, true); } /// @@ -2527,7 +2553,10 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez); sceneObject.RootPart.AddFlag(PrimFlags.Phantom); - AddRestoredSceneObject(sceneObject, false, false); + + // Don't sent a full update here because this will cause full updates to be sent twice for + // attachments on region crossings, resulting in viewer glitches. + AddRestoredSceneObject(sceneObject, false, false, false); // Handle attachment special case SceneObjectPart RootPrim = sceneObject.RootPart; @@ -2554,12 +2583,13 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat( "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition); + RootPrim.RemFlag(PrimFlags.TemporaryOnRez); + if (AttachmentsModule != null) AttachmentsModule.AttachObject( sp.ControllingClient, grp.LocalId, (uint)0, grp.GroupRotation, grp.AbsolutePosition, false); - - RootPrim.RemFlag(PrimFlags.TemporaryOnRez); - grp.SendGroupFullUpdate(); + + //grp.SendGroupFullUpdate(); } else { diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index a02f614387..5902080880 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -222,11 +222,15 @@ namespace OpenSim.Region.Framework.Scenes /// If true, we won't persist this object until it changes /// If false, we'll persist this object immediately /// + /// + /// If true, we send updates to the client to tell it about this object + /// If false, we leave it up to the caller to do this + /// /// /// true if the object was added, false if an object with the same uuid was already in the scene /// protected internal bool AddRestoredSceneObject( - SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted) + SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) { if (!alreadyPersisted) { @@ -234,9 +238,9 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.HasGroupChanged = true; } - return AddSceneObject(sceneObject, attachToBackup, true); + return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); } - + /// /// Add a newly created object to the scene. This will both update the scene, and send information about the /// new object to all clients interested in the scene. diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 837d3a2142..78c2566af6 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2012,7 +2012,8 @@ namespace OpenSim.Region.Framework.Scenes /// public void ScheduleGroupForFullUpdate() { -// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, UUID); + if (IsAttachment) + m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); checkAtTargets(); RootPart.ScheduleFullUpdate(); From db73b1c64e6f3a4ff139d89e2195327ffc2e09f5 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 8 Jun 2010 15:32:18 +0100 Subject: [PATCH 2/4] Adjust object update priorities such that root prims are sent to the viewer before child prims. This was originally a fix for huds, since child prims fail to display if the viewer doesn't receive the root prim update first. However, on the advice of jhurliman, this has been done for all objects, both ordinary and attachments. The separate mechanism in LLClientView which prevents child prim updates being sent out first is still present temporarily. This is a foreport of the equivalent fix in 0.6.9-post-fixes, though that was for attachments only. --- .../Region/Framework/Scenes/Prioritizer.cs | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index 1eb0c286e8..4780cdd569 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using log4net; using Nini.Config; @@ -32,6 +32,15 @@ namespace OpenSim.Region.Framework.Scenes public class Prioritizer { private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the + /// viewer before child prim updates. + /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up + /// being double. We do it both ways so that there is a still a priority delta even if the priority is already + /// double.MinValue or double.MaxValue. + /// + private double m_childPrimAdjustmentFactor = 0.05; private Scene m_scene; @@ -42,21 +51,50 @@ namespace OpenSim.Region.Framework.Scenes public double GetUpdatePriority(IClientAPI client, ISceneEntity entity) { + double priority = 0; + switch (m_scene.UpdatePrioritizationScheme) { case UpdatePrioritizationSchemes.Time: - return GetPriorityByTime(); + priority = GetPriorityByTime(); + break; case UpdatePrioritizationSchemes.Distance: - return GetPriorityByDistance(client, entity); + priority = GetPriorityByDistance(client, entity); + break; case UpdatePrioritizationSchemes.SimpleAngularDistance: - return GetPriorityByDistance(client, entity); // TODO: Reimplement SimpleAngularDistance + priority = GetPriorityByDistance(client, entity); // TODO: Reimplement SimpleAngularDistance + break; case UpdatePrioritizationSchemes.FrontBack: - return GetPriorityByFrontBack(client, entity); + priority = GetPriorityByFrontBack(client, entity); + break; case UpdatePrioritizationSchemes.BestAvatarResponsiveness: - return GetPriorityByBestAvatarResponsiveness(client, entity); + priority = GetPriorityByBestAvatarResponsiveness(client, entity); + break; default: throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); + break; } + + // Adjust priority so that root prims are sent to the viewer first. This is especially important for + // attachments acting as huds, since current viewers fail to display hud child prims if their updates + // arrive before the root one. + if (entity is SceneObjectPart) + { + SceneObjectPart sop = ((SceneObjectPart)entity); + + if (sop.IsRoot) + { + if (priority >= double.MinValue + m_childPrimAdjustmentFactor) + priority -= m_childPrimAdjustmentFactor; + } + else + { + if (priority <= double.MaxValue - m_childPrimAdjustmentFactor) + priority += m_childPrimAdjustmentFactor; + } + } + + return priority; } private double GetPriorityByTime() From 21246395be7160818e1220ec1b9905fb1ed96fe4 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 8 Jun 2010 15:38:53 +0100 Subject: [PATCH 3/4] Comment out the attachment update reordering mechanism in LLClientView since this doesn't appear necessary when the prim priorities are adjusted so that root prim updates are always sent before child prim updates. --- .../ClientStack/LindenUDP/LLClientView.cs | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 0e58986932..66631b545e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -331,7 +331,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// protected HashSet m_killRecord; - protected HashSet m_attachmentsSent; +// protected HashSet m_attachmentsSent; private int m_moneyBalance; private int m_animationSequenceNumber = 1; @@ -429,7 +429,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new HashSet(); - m_attachmentsSent = new HashSet(); +// m_attachmentsSent = new HashSet(); m_assetService = m_scene.RequestModuleInterface(); m_hyperAssets = m_scene.RequestModuleInterface(); @@ -3416,7 +3416,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(objupdate, ThrottleOutPacketType.Task); // We need to record the avatar local id since the root prim of an attachment points to this. - m_attachmentsSent.Add(avatar.LocalId); +// m_attachmentsSent.Add(avatar.LocalId); } public void SendCoarseLocationUpdate(List users, List CoarseLocations) @@ -3553,36 +3553,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) - { - SceneObjectPart sop = (SceneObjectPart)update.Entity; - string text = sop.Text; - if (text.IndexOf("\n") >= 0) - text = text.Remove(text.IndexOf("\n")); - - if (m_attachmentsSent.Contains(sop.ParentID)) - { +// if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) +// { +// SceneObjectPart sop = (SceneObjectPart)update.Entity; +// string text = sop.Text; +// if (text.IndexOf("\n") >= 0) +// text = text.Remove(text.IndexOf("\n")); +// +// if (m_attachmentsSent.Contains(sop.ParentID)) +// { +//// m_log.DebugFormat( +//// "[CLIENT]: Sending full info about attached prim {0} text {1}", +//// sop.LocalId, text); +// +// objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); +// +// m_attachmentsSent.Add(sop.LocalId); +// } +// else +// { // m_log.DebugFormat( -// "[CLIENT]: Sending full info about attached prim {0} text {1}", -// sop.LocalId, text); - - objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); - - m_attachmentsSent.Add(sop.LocalId); - } - else - { - m_log.DebugFormat( - "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", - sop.LocalId, text, sop.ParentID); - - m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); - } - } - else - { +// "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", +// sop.LocalId, text, sop.ParentID); +// +// m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); +// } +// } +// else +// { objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); - } +// } } } else if (!canUseImproved) From c8b301a644a8ebe37b5004b90d629a53d54ee25f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 8 Jun 2010 21:12:01 +0100 Subject: [PATCH 4/4] Improve instructions for [Groups] setup in OpenSim.ini.example --- bin/OpenSim.ini.example | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 2a70e9668e..38febc2835 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1171,44 +1171,42 @@ [Groups] Enabled = false - ; This is the current groups stub in Region.CoreModules.Avatar.Groups + ; This is the current groups stub in Region.CoreModules.Avatar.Groups. All the other settings below only really + ; apply to the Flotsam/SimianGrid GroupsModule Module = Default - ; The PHP code for the server is available from the Flotsam project for you to deploy - ; to your own server. The Flotsam project is located at http://code.google.com/p/flotsam/ - ; + ; This module can use a PHP XmlRpc server from the Flotsam project at http://code.google.com/p/flotsam/ + ; or from the SimianGrid project at http://code.google.com/p/openmetaverse ;Module = GroupsModule ; Enable Group Notices - ;NoticesEnabled = true + ;NoticesEnabled = true ; This makes the Groups modules very chatty on the console. DebugEnabled = false ; Specify which messaging module to use for groups messaging and if it's enabled ;MessagingModule = GroupsMessagingModule - ;MessagingEnabled = true + ;MessagingEnabled = true - ; Service connector to Groups Service [Select One] ServicesConnectorModule - - - ; Simian Grid Service for Groups + ; Service connectors to the Groups Service. Select one depending on whether you're using a Flotsam XmlRpc backend or a SimianGrid backend + + ; SimianGrid Service for Groups ;ServicesConnectorModule = SimianGroupsServicesConnector ;GroupsServerURI = http://mygridserver.com:82/Grid/ - ; XmlRpc Service Connector to the Flotsam XmlRpc Groups Service settings + ; Flotsam XmlRpc Service for Groups ;ServicesConnectorModule = XmlRpcGroupsServicesConnector ;GroupsServerURI = http://yourxmlrpcserver.com/xmlrpc.php - ; XmlRpc Service Settings - ;XmlRpcServiceReadKey = 1234 - ;XmlRpcServiceWriteKey = 1234 + ; XmlRpc Security settings. These must match those set on your backend groups service. + ;XmlRpcServiceReadKey = 1234 + ;XmlRpcServiceWriteKey = 1234 ; Disables HTTP Keep-Alive for XmlRpcGroupsServicesConnector HTTP Requests, ; this is a work around fora problem discovered on some Windows based region servers. ; Only disable keep alive if you see a large number (dozens) of the following Exceptions: ; System.Net.WebException: The request was aborted: The request was canceled. - ; ; XmlRpcDisableKeepAlive = false