diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 7851c4d5ad..f125822604 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3562,24 +3562,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP EntityUpdate update; while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update)) { - // 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. - // - // Receiving updates after kills results in undeleteable prims that persist until relog and - // currently occurs because prims can be deleted before all queued updates are sent. - if (m_killRecord.Contains(update.Entity.LocalId)) - { -// m_log.WarnFormat( -// "[CLIENT]: Preventing full update for prim with local id {0} after client for user {1} told it was deleted", -// update.Entity.LocalId, Name); - continue; - } - if (update.Entity is SceneObjectPart) { SceneObjectPart part = (SceneObjectPart)update.Entity; + // 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)) + { + // m_log.WarnFormat( + // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", + // part.LocalId, Name); + continue; + } + if (part.ParentGroup.IsAttachment && m_disableFacelights) { if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 5bf36e6f1d..e02783ad4d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -403,11 +403,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Queue an outgoing packet if appropriate. /// /// + /// Always queue the packet if at all possible. /// /// true if the packet has been queued, /// false if the packet has not been queued and should be sent immediately. /// - public bool EnqueueOutgoing(OutgoingPacket packet) + public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) { int category = (int)packet.Category; @@ -416,14 +417,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.LocklessQueue queue = m_packetOutboxes[category]; TokenBucket bucket = m_throttleCategories[category]; - if (bucket.RemoveTokens(packet.Buffer.DataLength)) + if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) { // Enough tokens were removed from the bucket, the packet will not be queued return false; } else { - // Not enough tokens in the bucket, queue this packet + // Force queue specified or not enough tokens in the bucket, queue this packet queue.Enqueue(packet); return true; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index ff4abf8997..e54cfc21ea 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -410,7 +410,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will + // continue to display the deleted object until relog. Therefore, we need to always queue a kill object + // packet so that it isn't sent before a queued update packet. + bool requestQueue = type == PacketType.KillObject; + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) SendPacketFinal(outgoingPacket); #endregion Queue or Send @@ -503,7 +507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //Interlocked.Increment(ref Stats.ResentPackets); // Requeue or resend the packet - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) SendPacketFinal(outgoingPacket); } }