aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs457
1 files changed, 233 insertions, 224 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 6a76069..196ac50 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -328,7 +328,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
328 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 328 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
329 /// ownerless phantom. 329 /// ownerless phantom.
330 /// 330 ///
331 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock 331 /// All manipulation of this set has to occur under a lock
332 /// 332 ///
333 /// </value> 333 /// </value>
334 protected HashSet<uint> m_killRecord; 334 protected HashSet<uint> m_killRecord;
@@ -1536,11 +1536,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1536 OutPacket(kill, ThrottleOutPacketType.State); 1536 OutPacket(kill, ThrottleOutPacketType.State);
1537 return; 1537 return;
1538 } 1538 }
1539 m_killRecord.Add(localIDs[0]); 1539 lock (m_killRecord)
1540 {
1541 m_killRecord.Add(localIDs[0]);
1542 }
1540 } 1543 }
1541 else 1544 else
1542 { 1545 {
1543 lock (m_entityUpdates.SyncRoot) 1546 lock (m_killRecord)
1544 { 1547 {
1545 foreach (uint localID in localIDs) 1548 foreach (uint localID in localIDs)
1546 m_killRecord.Add(localID); 1549 m_killRecord.Add(localID);
@@ -3595,248 +3598,254 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3595 int updatesThisCall = 0; 3598 int updatesThisCall = 0;
3596 3599
3597 EntityUpdate update; 3600 EntityUpdate update;
3598 while (updatesThisCall < maxUpdates) 3601 lock (m_killRecord)
3599 { 3602 {
3600 lock (m_entityUpdates.SyncRoot) 3603 while (updatesThisCall < maxUpdates)
3601 if (!m_entityUpdates.TryDequeue(out update)) 3604 {
3602 break; 3605 lock (m_entityUpdates.SyncRoot)
3606 if (!m_entityUpdates.TryDequeue(out update))
3607 break;
3603 3608
3604 if (update.Entity is SceneObjectPart) 3609 if (update.Entity is SceneObjectPart)
3605 { 3610 {
3606 SceneObjectPart part = (SceneObjectPart)update.Entity; 3611 SceneObjectPart part = (SceneObjectPart)update.Entity;
3607 3612
3608 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3613 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3609 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3614 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3610 // safety measure. 3615 // safety measure.
3611 // 3616 //
3612 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update 3617 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3613 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs 3618 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3614 // updates and kills on different threads with different scheduling strategies, hence this protection. 3619 // updates and kills on different threads with different scheduling strategies, hence this protection.
3615 // 3620 //
3616 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3621 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3617 // after the root prim has been deleted. 3622 // after the root prim has been deleted.
3618 if (m_killRecord.Contains(part.LocalId)) 3623 if (m_killRecord.Contains(part.LocalId))
3619 continue;
3620 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3621 continue;
3622
3623 if (part.ParentGroup.IsDeleted)
3624 continue;
3625
3626 if (part.ParentGroup.IsAttachment)
3627 { // Someone else's HUD, why are we getting these?
3628 if (part.ParentGroup.OwnerID != AgentId &&
3629 part.ParentGroup.RootPart.Shape.State >= 30)
3630 continue; 3624 continue;
3631 ScenePresence sp; 3625 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3632 // Owner is not in the sim, don't update it to
3633 // anyone
3634 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3635 continue; 3626 continue;
3636 3627
3637 List<SceneObjectGroup> atts = sp.Attachments; 3628 if (part.ParentGroup.IsDeleted)
3638 bool found = false; 3629 continue;
3639 foreach (SceneObjectGroup att in atts) 3630
3640 { 3631 if (part.ParentGroup.IsAttachment)
3641 if (att == part.ParentGroup) 3632 { // Someone else's HUD, why are we getting these?
3633 if (part.ParentGroup.OwnerID != AgentId &&
3634 part.ParentGroup.RootPart.Shape.State >= 30)
3635 continue;
3636 ScenePresence sp;
3637 // Owner is not in the sim, don't update it to
3638 // anyone
3639 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3640 continue;
3641
3642 List<SceneObjectGroup> atts = sp.Attachments;
3643 bool found = false;
3644 foreach (SceneObjectGroup att in atts)
3642 { 3645 {
3643 found = true; 3646 if (att == part.ParentGroup)
3644 break; 3647 {
3648 found = true;
3649 break;
3650 }
3645 } 3651 }
3646 }
3647 3652
3648 // It's an attachment of a valid avatar, but 3653 // It's an attachment of a valid avatar, but
3649 // doesn't seem to be attached, skip 3654 // doesn't seem to be attached, skip
3650 if (!found) 3655 if (!found)
3651 continue; 3656 continue;
3652 } 3657 }
3653 3658
3654 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3659 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3655 {
3656 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3657 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3658 { 3660 {
3659 part.Shape.LightEntry = false; 3661 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3662 {
3663 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3664 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3665 {
3666 part.Shape.LightEntry = false;
3667 }
3668 }
3669 }
3670
3671 ++updatesThisCall;
3672
3673 #region UpdateFlags to packet type conversion
3674
3675 PrimUpdateFlags updateFlags = update.Flags;
3676
3677 bool canUseCompressed = true;
3678 bool canUseImproved = true;
3679
3680 // Compressed object updates only make sense for LL primitives
3681 if (!(update.Entity is SceneObjectPart))
3682 {
3683 canUseCompressed = false;
3660 } 3684 }
3685
3686 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3687 {
3688 canUseCompressed = false;
3689 canUseImproved = false;
3690 }
3691 else
3692 {
3693 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3694 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3695 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3696 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3697 {
3698 canUseCompressed = false;
3699 }
3700
3701 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3702 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3703 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3704 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3705 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3706 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3707 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3708 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3709 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3710 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3711 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3712 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3713 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3714 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3715 {
3716 canUseImproved = false;
3717 }
3718 }
3719
3720 #endregion UpdateFlags to packet type conversion
3721
3722 #region Block Construction
3723
3724 // TODO: Remove this once we can build compressed updates
3725 canUseCompressed = false;
3726
3727 if (!canUseImproved && !canUseCompressed)
3728 {
3729 if (update.Entity is ScenePresence)
3730 {
3731 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3732 }
3733 else
3734 {
3735 // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3736 // {
3737 // SceneObjectPart sop = (SceneObjectPart)update.Entity;
3738 // string text = sop.Text;
3739 // if (text.IndexOf("\n") >= 0)
3740 // text = text.Remove(text.IndexOf("\n"));
3741 //
3742 // if (m_attachmentsSent.Contains(sop.ParentID))
3743 // {
3744 //// m_log.DebugFormat(
3745 //// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3746 //// sop.LocalId, text);
3747 //
3748 // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3749 //
3750 // m_attachmentsSent.Add(sop.LocalId);
3751 // }
3752 // else
3753 // {
3754 // m_log.DebugFormat(
3755 // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3756 // sop.LocalId, text, sop.ParentID);
3757 //
3758 // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3759 // }
3760 // }
3761 // else
3762 // {
3763 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3764 // }
3765 }
3766 }
3767 else if (!canUseImproved)
3768 {
3769 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3770 }
3771 else
3772 {
3773 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3774 // Self updates go into a special list
3775 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3776 else
3777 // Everything else goes here
3778 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3779 }
3780
3781 #endregion Block Construction
3661 } 3782 }
3662 } 3783
3663 3784 #region Packet Sending
3664 ++updatesThisCall; 3785
3665 3786 const float TIME_DILATION = 1.0f;
3666 #region UpdateFlags to packet type conversion 3787 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
3667 3788
3668 PrimUpdateFlags updateFlags = update.Flags; 3789 if (terseAgentUpdateBlocks.IsValueCreated)
3669
3670 bool canUseCompressed = true;
3671 bool canUseImproved = true;
3672
3673 // Compressed object updates only make sense for LL primitives
3674 if (!(update.Entity is SceneObjectPart))
3675 {
3676 canUseCompressed = false;
3677 }
3678
3679 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3680 {
3681 canUseCompressed = false;
3682 canUseImproved = false;
3683 }
3684 else
3685 {
3686 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3687 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3688 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3689 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3690 { 3790 {
3691 canUseCompressed = false; 3791 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3792
3793 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3794 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3795 packet.RegionData.TimeDilation = timeDilation;
3796 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3797
3798 for (int i = 0; i < blocks.Count; i++)
3799 packet.ObjectData[i] = blocks[i];
3800
3801 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3692 } 3802 }
3693 3803
3694 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || 3804 if (objectUpdateBlocks.IsValueCreated)
3695 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3696 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3697 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3698 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3699 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3700 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3701 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3702 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3703 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3704 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3705 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3706 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3707 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3708 { 3805 {
3709 canUseImproved = false; 3806 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3807
3808 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3809 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3810 packet.RegionData.TimeDilation = timeDilation;
3811 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3812
3813 for (int i = 0; i < blocks.Count; i++)
3814 packet.ObjectData[i] = blocks[i];
3815
3816 OutPacket(packet, ThrottleOutPacketType.Task, true);
3710 } 3817 }
3711 } 3818
3712 3819 if (compressedUpdateBlocks.IsValueCreated)
3713 #endregion UpdateFlags to packet type conversion
3714
3715 #region Block Construction
3716
3717 // TODO: Remove this once we can build compressed updates
3718 canUseCompressed = false;
3719
3720 if (!canUseImproved && !canUseCompressed)
3721 {
3722 if (update.Entity is ScenePresence)
3723 { 3820 {
3724 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); 3821 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3822
3823 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3824 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3825 packet.RegionData.TimeDilation = timeDilation;
3826 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3827
3828 for (int i = 0; i < blocks.Count; i++)
3829 packet.ObjectData[i] = blocks[i];
3830
3831 OutPacket(packet, ThrottleOutPacketType.Task, true);
3725 } 3832 }
3726 else 3833
3834 if (terseUpdateBlocks.IsValueCreated)
3727 { 3835 {
3728// if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) 3836 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3729// { 3837
3730// SceneObjectPart sop = (SceneObjectPart)update.Entity; 3838 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3731// string text = sop.Text; 3839 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3732// if (text.IndexOf("\n") >= 0) 3840 packet.RegionData.TimeDilation = timeDilation;
3733// text = text.Remove(text.IndexOf("\n")); 3841 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3734// 3842
3735// if (m_attachmentsSent.Contains(sop.ParentID)) 3843 for (int i = 0; i < blocks.Count; i++)
3736// { 3844 packet.ObjectData[i] = blocks[i];
3737//// m_log.DebugFormat( 3845
3738//// "[CLIENT]: Sending full info about attached prim {0} text {1}", 3846 OutPacket(packet, ThrottleOutPacketType.Task, true);
3739//// sop.LocalId, text);
3740//
3741// objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3742//
3743// m_attachmentsSent.Add(sop.LocalId);
3744// }
3745// else
3746// {
3747// m_log.DebugFormat(
3748// "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3749// sop.LocalId, text, sop.ParentID);
3750//
3751// m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3752// }
3753// }
3754// else
3755// {
3756 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3757// }
3758 } 3847 }
3759 } 3848 }
3760 else if (!canUseImproved)
3761 {
3762 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3763 }
3764 else
3765 {
3766 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3767 // Self updates go into a special list
3768 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3769 else
3770 // Everything else goes here
3771 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3772 }
3773
3774 #endregion Block Construction
3775 }
3776
3777 #region Packet Sending
3778
3779 const float TIME_DILATION = 1.0f;
3780 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
3781
3782 if (terseAgentUpdateBlocks.IsValueCreated)
3783 {
3784 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3785
3786 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3787 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3788 packet.RegionData.TimeDilation = timeDilation;
3789 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3790
3791 for (int i = 0; i < blocks.Count; i++)
3792 packet.ObjectData[i] = blocks[i];
3793
3794 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3795 }
3796
3797 if (objectUpdateBlocks.IsValueCreated)
3798 {
3799 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3800
3801 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3802 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3803 packet.RegionData.TimeDilation = timeDilation;
3804 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3805
3806 for (int i = 0; i < blocks.Count; i++)
3807 packet.ObjectData[i] = blocks[i];
3808
3809 OutPacket(packet, ThrottleOutPacketType.Task, true);
3810 }
3811
3812 if (compressedUpdateBlocks.IsValueCreated)
3813 {
3814 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3815
3816 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3817 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3818 packet.RegionData.TimeDilation = timeDilation;
3819 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3820
3821 for (int i = 0; i < blocks.Count; i++)
3822 packet.ObjectData[i] = blocks[i];
3823
3824 OutPacket(packet, ThrottleOutPacketType.Task, true);
3825 }
3826
3827 if (terseUpdateBlocks.IsValueCreated)
3828 {
3829 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3830
3831 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3832 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3833 packet.RegionData.TimeDilation = timeDilation;
3834 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3835
3836 for (int i = 0; i < blocks.Count; i++)
3837 packet.ObjectData[i] = blocks[i];
3838
3839 OutPacket(packet, ThrottleOutPacketType.Task, true);
3840 } 3849 }
3841 3850
3842 #endregion Packet Sending 3851 #endregion Packet Sending