diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 6a76069fb5..196ac5004e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -328,7 +328,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an /// ownerless phantom. /// - /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock + /// All manipulation of this set has to occur under a lock /// /// protected HashSet m_killRecord; @@ -1536,11 +1536,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(kill, ThrottleOutPacketType.State); return; } - m_killRecord.Add(localIDs[0]); + lock (m_killRecord) + { + m_killRecord.Add(localIDs[0]); + } } else { - lock (m_entityUpdates.SyncRoot) + lock (m_killRecord) { foreach (uint localID in localIDs) m_killRecord.Add(localID); @@ -3595,248 +3598,254 @@ namespace OpenSim.Region.ClientStack.LindenUDP int updatesThisCall = 0; EntityUpdate update; - while (updatesThisCall < maxUpdates) + lock (m_killRecord) { - lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update)) - break; - - if (update.Entity is SceneObjectPart) + while (updatesThisCall < maxUpdates) { - SceneObjectPart part = (SceneObjectPart)update.Entity; + lock (m_entityUpdates.SyncRoot) + if (!m_entityUpdates.TryDequeue(out update)) + break; - // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client - // will never receive an update after a prim kill. Even then, keeping the kill record may be a good - // safety measure. - // - // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update - // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs - // updates and kills on different threads with different scheduling strategies, hence this protection. - // - // This doesn't appear to apply to child prims - a client will happily ignore these updates - // after the root prim has been deleted. - if (m_killRecord.Contains(part.LocalId)) - continue; - if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId)) - continue; + if (update.Entity is SceneObjectPart) + { + SceneObjectPart part = (SceneObjectPart)update.Entity; - if (part.ParentGroup.IsDeleted) - continue; - - if (part.ParentGroup.IsAttachment) - { // Someone else's HUD, why are we getting these? - if (part.ParentGroup.OwnerID != AgentId && - part.ParentGroup.RootPart.Shape.State >= 30) + // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client + // will never receive an update after a prim kill. Even then, keeping the kill record may be a good + // safety measure. + // + // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update + // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs + // updates and kills on different threads with different scheduling strategies, hence this protection. + // + // This doesn't appear to apply to child prims - a client will happily ignore these updates + // after the root prim has been deleted. + if (m_killRecord.Contains(part.LocalId)) continue; - ScenePresence sp; - // Owner is not in the sim, don't update it to - // anyone - if (!m_scene.TryGetScenePresence(part.OwnerID, out sp)) + if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId)) continue; - List atts = sp.Attachments; - bool found = false; - foreach (SceneObjectGroup att in atts) - { - if (att == part.ParentGroup) + if (part.ParentGroup.IsDeleted) + continue; + + if (part.ParentGroup.IsAttachment) + { // Someone else's HUD, why are we getting these? + if (part.ParentGroup.OwnerID != AgentId && + part.ParentGroup.RootPart.Shape.State >= 30) + continue; + ScenePresence sp; + // Owner is not in the sim, don't update it to + // anyone + if (!m_scene.TryGetScenePresence(part.OwnerID, out sp)) + continue; + + List atts = sp.Attachments; + bool found = false; + foreach (SceneObjectGroup att in atts) { - found = true; - break; + if (att == part.ParentGroup) + { + found = true; + break; + } + } + + // It's an attachment of a valid avatar, but + // doesn't seem to be attached, skip + if (!found) + continue; + } + + if (part.ParentGroup.IsAttachment && m_disableFacelights) + { + if (part.ParentGroup.IsAttachment && m_disableFacelights) + { + if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && + part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) + { + part.Shape.LightEntry = false; + } } } - - // It's an attachment of a valid avatar, but - // doesn't seem to be attached, skip - if (!found) - continue; - } - - if (part.ParentGroup.IsAttachment && m_disableFacelights) - { - if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && - part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) + + ++updatesThisCall; + + #region UpdateFlags to packet type conversion + + PrimUpdateFlags updateFlags = update.Flags; + + bool canUseCompressed = true; + bool canUseImproved = true; + + // Compressed object updates only make sense for LL primitives + if (!(update.Entity is SceneObjectPart)) { - part.Shape.LightEntry = false; + canUseCompressed = false; } - } - } - - ++updatesThisCall; - - #region UpdateFlags to packet type conversion - - PrimUpdateFlags updateFlags = update.Flags; - - bool canUseCompressed = true; - bool canUseImproved = true; - - // Compressed object updates only make sense for LL primitives - if (!(update.Entity is SceneObjectPart)) - { - canUseCompressed = false; - } - - if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) - { - canUseCompressed = false; - canUseImproved = false; - } - else - { - if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || - updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || - updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || - updateFlags.HasFlag(PrimUpdateFlags.Joint)) - { + + if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) + { + canUseCompressed = false; + canUseImproved = false; + } + else + { + if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || + updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || + updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || + updateFlags.HasFlag(PrimUpdateFlags.Joint)) + { + canUseCompressed = false; + } + + if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || + updateFlags.HasFlag(PrimUpdateFlags.ParentID) || + updateFlags.HasFlag(PrimUpdateFlags.Scale) || + updateFlags.HasFlag(PrimUpdateFlags.PrimData) || + updateFlags.HasFlag(PrimUpdateFlags.Text) || + updateFlags.HasFlag(PrimUpdateFlags.NameValue) || + updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || + updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || + updateFlags.HasFlag(PrimUpdateFlags.Sound) || + updateFlags.HasFlag(PrimUpdateFlags.Particles) || + updateFlags.HasFlag(PrimUpdateFlags.Material) || + updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || + updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || + updateFlags.HasFlag(PrimUpdateFlags.Joint)) + { + canUseImproved = false; + } + } + + #endregion UpdateFlags to packet type conversion + + #region Block Construction + + // TODO: Remove this once we can build compressed updates canUseCompressed = false; + + if (!canUseImproved && !canUseCompressed) + { + if (update.Entity is ScenePresence) + { + objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); + } + 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)) + // { + //// 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) + { + compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); + } + else + { + if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) + // Self updates go into a special list + terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); + else + // Everything else goes here + terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); + } + + #endregion Block Construction } - - if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || - updateFlags.HasFlag(PrimUpdateFlags.ParentID) || - updateFlags.HasFlag(PrimUpdateFlags.Scale) || - updateFlags.HasFlag(PrimUpdateFlags.PrimData) || - updateFlags.HasFlag(PrimUpdateFlags.Text) || - updateFlags.HasFlag(PrimUpdateFlags.NameValue) || - updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || - updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || - updateFlags.HasFlag(PrimUpdateFlags.Sound) || - updateFlags.HasFlag(PrimUpdateFlags.Particles) || - updateFlags.HasFlag(PrimUpdateFlags.Material) || - updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || - updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || - updateFlags.HasFlag(PrimUpdateFlags.Joint)) + + #region Packet Sending + + const float TIME_DILATION = 1.0f; + ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); + + if (terseAgentUpdateBlocks.IsValueCreated) { - canUseImproved = false; + List blocks = terseAgentUpdateBlocks.Value; + + ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); + packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; + packet.RegionData.TimeDilation = timeDilation; + packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + OutPacket(packet, ThrottleOutPacketType.Unknown, true); } - } - - #endregion UpdateFlags to packet type conversion - - #region Block Construction - - // TODO: Remove this once we can build compressed updates - canUseCompressed = false; - - if (!canUseImproved && !canUseCompressed) - { - if (update.Entity is ScenePresence) + + if (objectUpdateBlocks.IsValueCreated) { - objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); + List blocks = objectUpdateBlocks.Value; + + ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); + packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; + packet.RegionData.TimeDilation = timeDilation; + packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + OutPacket(packet, ThrottleOutPacketType.Task, true); } - else + + if (compressedUpdateBlocks.IsValueCreated) { -// 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)); -// } + List blocks = compressedUpdateBlocks.Value; + + ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); + packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; + packet.RegionData.TimeDilation = timeDilation; + packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; + + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + OutPacket(packet, ThrottleOutPacketType.Task, true); + } + + if (terseUpdateBlocks.IsValueCreated) + { + List blocks = terseUpdateBlocks.Value; + + ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); + packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; + packet.RegionData.TimeDilation = timeDilation; + packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + OutPacket(packet, ThrottleOutPacketType.Task, true); } } - else if (!canUseImproved) - { - compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); - } - else - { - if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) - // Self updates go into a special list - terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); - else - // Everything else goes here - terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); - } - - #endregion Block Construction - } - - #region Packet Sending - - const float TIME_DILATION = 1.0f; - ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); - - if (terseAgentUpdateBlocks.IsValueCreated) - { - List blocks = terseAgentUpdateBlocks.Value; - - ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; - - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; - - OutPacket(packet, ThrottleOutPacketType.Unknown, true); - } - - if (objectUpdateBlocks.IsValueCreated) - { - List blocks = objectUpdateBlocks.Value; - - ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; - - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; - - OutPacket(packet, ThrottleOutPacketType.Task, true); - } - - if (compressedUpdateBlocks.IsValueCreated) - { - List blocks = compressedUpdateBlocks.Value; - - ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; - - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; - - OutPacket(packet, ThrottleOutPacketType.Task, true); - } - - if (terseUpdateBlocks.IsValueCreated) - { - List blocks = terseUpdateBlocks.Value; - - ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; - - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; - - OutPacket(packet, ThrottleOutPacketType.Task, true); } #endregion Packet Sending diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f81030c746..45625d69b1 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -152,7 +152,7 @@ namespace OpenSim.Region.Framework.Scenes private int m_update_backup = 200; private int m_update_terrain = 50; private int m_update_land = 1; - private int m_update_coarse_locations = 50; + private int m_update_coarse_locations = 80; private int frameMS; private int physicsMS2; @@ -181,6 +181,8 @@ namespace OpenSim.Region.Framework.Scenes private object m_deleting_scene_object = new object(); private object m_cleaningAttachments = new object(); + private bool m_cleaningTemps = false; + private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time; private bool m_reprioritizationEnabled = true; private double m_reprioritizationInterval = 5000.0; @@ -1296,10 +1298,11 @@ namespace OpenSim.Region.Framework.Scenes physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS); // Delete temp-on-rez stuff - if (m_frame % m_update_backup == 0) + if (m_frame % 1000 == 0 && !m_cleaningTemps) { int tmpTempOnRezMS = Util.EnvironmentTickCount(); - CleanTempObjects(); + m_cleaningTemps = true; + Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; }); tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpTempOnRezMS); } @@ -1326,12 +1329,12 @@ namespace OpenSim.Region.Framework.Scenes terrainMS = Util.EnvironmentTickCountSubtract(terMS); } - if (m_frame % m_update_land == 0) - { - int ldMS = Util.EnvironmentTickCount(); - UpdateLand(); - landMS = Util.EnvironmentTickCountSubtract(ldMS); - } + //if (m_frame % m_update_land == 0) + //{ + // int ldMS = Util.EnvironmentTickCount(); + // UpdateLand(); + // landMS = Util.EnvironmentTickCountSubtract(ldMS); + //} frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS); otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; @@ -1424,13 +1427,12 @@ namespace OpenSim.Region.Framework.Scenes private void CheckAtTargets() { + Dictionary.ValueCollection objs; lock (m_groupsWithTargets) - { - foreach (SceneObjectGroup entry in m_groupsWithTargets.Values) - { - entry.checkAtTargets(); - } - } + objs = m_groupsWithTargets.Values; + + foreach (SceneObjectGroup entry in objs) + entry.checkAtTargets(); } @@ -4539,6 +4541,7 @@ namespace OpenSim.Region.Framework.Scenes } } } + } public void DeleteFromStorage(UUID uuid) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d83ff51d32..254fe37216 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2635,6 +2635,8 @@ namespace OpenSim.Region.Framework.Scenes #region Overridden Methods + private bool sendingPrims = false; + public override void Update() { const float ROTATION_TOLERANCE = 0.01f; @@ -2642,7 +2644,8 @@ namespace OpenSim.Region.Framework.Scenes const float POSITION_TOLERANCE = 0.05f; //const int TIME_MS_TOLERANCE = 3000; - + if (!sendingPrims) + Util.FireAndForget(delegate { sendingPrims = true; SendPrimUpdates(); sendingPrims = false; }); if (m_isChildAgent == false) { @@ -2670,6 +2673,7 @@ namespace OpenSim.Region.Framework.Scenes // followed suggestion from mic bowman. reversed the two lines below. if (m_parentID == 0 && m_physicsActor != null || m_parentID != 0) // Check that we have a physics actor or we're sitting on something CheckForBorderCrossing(); + CheckForSignificantMovement(); // sends update to the modules. } diff --git a/prebuild.xml b/prebuild.xml index 7dd7b67bd1..380e98b613 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -3037,6 +3037,7 @@ +