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();