From a4304fb9e6ec94b9a2aa70db85a68b9b102d4c33 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Thu, 13 Mar 2008 00:22:38 +0000 Subject: [PATCH] * Fix Mantis 761 (linking and delinking prims rapidly caused prims to 'disappear') * Root cause was that if two updates occurred in the same second of time, the second one was never sent * Linking/delinking appears to be okay now --- .../Region/Environment/Scenes/InnerScene.cs | 6 ++++ OpenSim/Region/Environment/Scenes/Scene.cs | 2 +- .../Environment/Scenes/SceneObjectGroup.cs | 14 +++++++-- .../Environment/Scenes/SceneObjectPart.cs | 22 ++++++++++---- .../Environment/Scenes/ScenePresence.cs | 30 ++++++++++++------- 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/Environment/Scenes/InnerScene.cs b/OpenSim/Region/Environment/Scenes/InnerScene.cs index e195c925a0..0272a7eb9e 100644 --- a/OpenSim/Region/Environment/Scenes/InnerScene.cs +++ b/OpenSim/Region/Environment/Scenes/InnerScene.cs @@ -206,6 +206,12 @@ namespace OpenSim.Region.Environment.Scenes } } + /// + /// Add an entity to the list of prims to process on the next update + /// + /// + /// A + /// internal void AddToUpdateList(EntityBase obj) { lock (m_updateList) diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 1a73e789b9..7ea528ce35 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -614,7 +614,7 @@ namespace OpenSim.Region.Environment.Scenes } /// - /// + /// Start the timer which triggers regular scene updates /// public void StartTimer() { diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index 1a3246037b..50dc2ae9a9 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -247,9 +247,11 @@ namespace OpenSim.Region.Environment.Scenes public SceneObjectGroup(Scene scene, ulong regionHandle, SceneObjectPart part) { m_scene = scene; + part.SetParent(this); part.ParentID = 0; part.LinkNum = 0; + m_parts.Add(part.UUID, part); SetPartAsRoot(part); @@ -691,7 +693,7 @@ namespace OpenSim.Region.Environment.Scenes #region Scheduling /// - /// + /// Examine this object's parts to see if they've changed sufficiently to warrant an update /// public override void Update() { @@ -703,6 +705,7 @@ namespace OpenSim.Region.Environment.Scenes } lastPhysGroupPos = AbsolutePosition; } + if ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) || (Math.Abs(lastPhysGroupRot.Y - GroupRotation.Y) > 0.1) @@ -714,6 +717,7 @@ namespace OpenSim.Region.Environment.Scenes } lastPhysGroupRot = GroupRotation; } + foreach (SceneObjectPart part in m_parts.Values) { part.SendScheduledUpdates(); @@ -737,7 +741,7 @@ namespace OpenSim.Region.Environment.Scenes } /// - /// + /// Schedule a full update for every part in this object /// public void ScheduleGroupForFullUpdate() { @@ -910,6 +914,7 @@ namespace OpenSim.Region.Environment.Scenes linkPart.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w); linkPart.ParentID = m_rootPart.LocalId; + linkPart.LinkNum = m_parts.Count; m_parts.Add(linkPart.UUID, linkPart); @@ -1015,7 +1020,7 @@ namespace OpenSim.Region.Environment.Scenes //m_rootPart.DoPhysicsPropertyUpdate(m_rootPart.PhysActor.IsPhysical, true); //} - SceneObjectGroup objectGroup = new SceneObjectGroup(m_scene, m_regionHandle, linkPart); + SceneObjectGroup objectGroup = new SceneObjectGroup(m_scene, m_regionHandle, linkPart); m_scene.AddEntity(objectGroup); @@ -1715,6 +1720,9 @@ namespace OpenSim.Region.Environment.Scenes m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId); } + /// + /// Completely delete this group and tell all the scene presences about that deletion. + /// public void DeleteGroup() { DetachFromBackup(this); diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index f20a638b78..b708d04fd8 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs @@ -132,7 +132,12 @@ namespace OpenSim.Region.Environment.Scenes [XmlIgnore] public uint TimeStampLastActivity = 0; // Will be used for AutoReturn /// - /// Only used internally to schedule client updates + /// Only used internally to schedule client updates. + /// 0 - no update is scheduled + /// 1 - terse update scheduled + /// 2 - full update scheduled + /// + /// TODO - This should be an enumeration /// private byte m_updateFlag; @@ -1090,7 +1095,7 @@ namespace OpenSim.Region.Environment.Scenes #region Update Scheduling /// - /// + /// Clear all pending updates /// private void ClearUpdateSchedule() { @@ -1098,7 +1103,7 @@ namespace OpenSim.Region.Environment.Scenes } /// - /// + /// Schedules this prim for a full update /// public void ScheduleFullUpdate() { @@ -1107,6 +1112,7 @@ namespace OpenSim.Region.Environment.Scenes m_parentGroup.HasGroupChanged = true; m_parentGroup.QueueForUpdateCheck(); } + TimeStampFull = (uint) Util.UnixTimeSinceEpoch(); m_updateFlag = 2; } @@ -1156,7 +1162,7 @@ namespace OpenSim.Region.Environment.Scenes } /// - /// + /// Tell all the prims which have had updates scheduled /// public void SendScheduledUpdates() { @@ -1688,7 +1694,10 @@ namespace OpenSim.Region.Environment.Scenes } #region Client Update Methods - + + /// + /// Tell all scene presences that they should send updates for this part to their clients + /// public void AddFullUpdateToAllAvatars() { List avatars = m_parentGroup.GetScenePresences(); @@ -1697,6 +1706,7 @@ namespace OpenSim.Region.Environment.Scenes avatars[i].QueuePartForUpdate(this); } } + public void SendFullUpdateToAllClientsExcept(LLUUID agentID) { List avatars = m_parentGroup.GetScenePresences(); @@ -1710,6 +1720,8 @@ namespace OpenSim.Region.Environment.Scenes } } } + + public void AddFullUpdateToAvatar(ScenePresence presence) { presence.QueuePartForUpdate(this); diff --git a/OpenSim/Region/Environment/Scenes/ScenePresence.cs b/OpenSim/Region/Environment/Scenes/ScenePresence.cs index fc13ebb0a2..2f35fe3c2b 100644 --- a/OpenSim/Region/Environment/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Environment/Scenes/ScenePresence.cs @@ -418,6 +418,10 @@ namespace OpenSim.Region.Environment.Scenes #endregion + /// + /// Add the part to the queue of parts for which we need to send an update to the client + /// + /// public void QueuePartForUpdate(SceneObjectPart part) { //if (InterestList.Contains(part.ParentGroup)) @@ -434,6 +438,11 @@ namespace OpenSim.Region.Environment.Scenes return m_scene.PermissionsMngr.GenerateClientFlags(m_uuid, ObjectID); } + /// + /// Send updates to the client about prims which have been placed on the update queue. We don't + /// necessarily send updates for all the parts on the queue, e.g. if an updates with a more recent + /// timestamp has already been sent. + /// public void SendPrimUpdates() { // if (m_scene.QuadTree.GetNodeID(this.AbsolutePosition.X, this.AbsolutePosition.Y) != m_currentQuadNode) @@ -446,13 +455,12 @@ namespace OpenSim.Region.Environment.Scenes if (!m_gotAllObjectsInScene) { if (!m_isChildAgent || m_scene.m_seeIntoRegionFromNeighbor) - { - + { m_scene.SendAllSceneObjectsToClient(this); - m_gotAllObjectsInScene = true; - + m_gotAllObjectsInScene = true; } } + if (m_partsUpdateQueue.Count > 0) { bool runUpdate = true; @@ -465,16 +473,18 @@ namespace OpenSim.Region.Environment.Scenes ScenePartUpdate update = m_updateTimes[part.UUID]; // Two updates can occur with the same timestamp (especially - // since our timestamp resolution is to the nearest second). The first - // could have been sent in the last update - we still need to send the - // second here. - - if (update.LastFullUpdateTime < part.TimeStampFull) + // since our timestamp resolution is to the nearest second). Therefore, we still need + // to send an update even if the last full update time is identical to the part's + // update timestamp. + // + // If we don't do this, various events (such as linking and delinking in the same + // second), will stop working properly! + if (update.LastFullUpdateTime <= part.TimeStampFull) { //need to do a full update part.SendFullUpdate(ControllingClient, GenerateClientFlags(part.UUID)); - // We'll update to the part's timestamp rather than the current to + // We'll update to the part's timestamp rather than the current time to // avoid the race condition whereby the next tick occurs while we are // doing this update. If this happened, then subsequent updates which occurred // on the same tick or the next tick of the last update would be ignored.