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 c4db5da2da..e02783ad4d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -399,7 +399,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return data;
}
- public bool EnqueueOutgoing(OutgoingPacket packet)
+ ///
+ /// 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, bool forceQueue)
{
int category = (int)packet.Category;
@@ -408,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 b5d8ec8dc5..e54cfc21ea 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -312,6 +312,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
+ ///
+ /// Start the process of sending a packet to the client.
+ ///
+ ///
+ ///
+ ///
+ ///
public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
{
// CoarseLocationUpdate packets cannot be split in an automated way
@@ -339,6 +346,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
+ ///
+ /// Start the process of sending a packet to the client.
+ ///
+ ///
+ ///
+ ///
+ ///
public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
{
int dataLength = data.Length;
@@ -396,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
@@ -489,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);
}
}