aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
authorMelanie2010-12-16 20:11:26 +0100
committerMelanie2010-12-16 20:11:26 +0100
commit4719e925b857ca4ebbe52cdf1cae0cd31cdfd0d0 (patch)
tree555ce114bccd0adf1c627c56e8bb90d857196f11 /OpenSim/Region/ClientStack
parentMerge branch 'master' into careminster-presence-refactor (diff)
downloadopensim-SC_OLD-4719e925b857ca4ebbe52cdf1cae0cd31cdfd0d0.zip
opensim-SC_OLD-4719e925b857ca4ebbe52cdf1cae0cd31cdfd0d0.tar.gz
opensim-SC_OLD-4719e925b857ca4ebbe52cdf1cae0cd31cdfd0d0.tar.bz2
opensim-SC_OLD-4719e925b857ca4ebbe52cdf1cae0cd31cdfd0d0.tar.xz
Revert the locking changes in LLCLientView
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs457
1 files changed, 224 insertions, 233 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 196ac50..6a76069 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 a lock 331 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
332 /// 332 ///
333 /// </value> 333 /// </value>
334 protected HashSet<uint> m_killRecord; 334 protected HashSet<uint> m_killRecord;
@@ -1536,14 +1536,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1536 OutPacket(kill, ThrottleOutPacketType.State); 1536 OutPacket(kill, ThrottleOutPacketType.State);
1537 return; 1537 return;
1538 } 1538 }
1539 lock (m_killRecord) 1539 m_killRecord.Add(localIDs[0]);
1540 {
1541 m_killRecord.Add(localIDs[0]);
1542 }
1543 } 1540 }
1544 else 1541 else
1545 { 1542 {
1546 lock (m_killRecord) 1543 lock (m_entityUpdates.SyncRoot)
1547 { 1544 {
1548 foreach (uint localID in localIDs) 1545 foreach (uint localID in localIDs)
1549 m_killRecord.Add(localID); 1546 m_killRecord.Add(localID);
@@ -3598,254 +3595,248 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3598 int updatesThisCall = 0; 3595 int updatesThisCall = 0;
3599 3596
3600 EntityUpdate update; 3597 EntityUpdate update;
3601 lock (m_killRecord) 3598 while (updatesThisCall < maxUpdates)
3602 { 3599 {
3603 while (updatesThisCall < maxUpdates) 3600 lock (m_entityUpdates.SyncRoot)
3604 { 3601 if (!m_entityUpdates.TryDequeue(out update))
3605 lock (m_entityUpdates.SyncRoot) 3602 break;
3606 if (!m_entityUpdates.TryDequeue(out update))
3607 break;
3608 3603
3609 if (update.Entity is SceneObjectPart) 3604 if (update.Entity is SceneObjectPart)
3610 { 3605 {
3611 SceneObjectPart part = (SceneObjectPart)update.Entity; 3606 SceneObjectPart part = (SceneObjectPart)update.Entity;
3612 3607
3613 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3608 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3614 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3609 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3615 // safety measure. 3610 // safety measure.
3616 // 3611 //
3617 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update 3612 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3618 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs 3613 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3619 // updates and kills on different threads with different scheduling strategies, hence this protection. 3614 // updates and kills on different threads with different scheduling strategies, hence this protection.
3620 // 3615 //
3621 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3616 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3622 // after the root prim has been deleted. 3617 // after the root prim has been deleted.
3623 if (m_killRecord.Contains(part.LocalId)) 3618 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)
3624 continue; 3630 continue;
3625 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId)) 3631 ScenePresence sp;
3632 // Owner is not in the sim, don't update it to
3633 // anyone
3634 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3626 continue; 3635 continue;
3627 3636
3628 if (part.ParentGroup.IsDeleted) 3637 List<SceneObjectGroup> atts = sp.Attachments;
3629 continue; 3638 bool found = false;
3630 3639 foreach (SceneObjectGroup att in atts)
3631 if (part.ParentGroup.IsAttachment)
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)
3645 {
3646 if (att == part.ParentGroup)
3647 {
3648 found = true;
3649 break;
3650 }
3651 }
3652
3653 // It's an attachment of a valid avatar, but
3654 // doesn't seem to be attached, skip
3655 if (!found)
3656 continue;
3657 }
3658
3659 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3660 { 3640 {
3661 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3641 if (att == part.ParentGroup)
3662 { 3642 {
3663 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3643 found = true;
3664 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) 3644 break;
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;
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 } 3645 }
3766 } 3646 }
3767 else if (!canUseImproved) 3647
3768 { 3648 // It's an attachment of a valid avatar, but
3769 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3649 // doesn't seem to be attached, skip
3770 } 3650 if (!found)
3771 else 3651 continue;
3652 }
3653
3654 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)
3772 { 3658 {
3773 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3659 part.Shape.LightEntry = false;
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 } 3660 }
3780
3781 #endregion Block Construction
3782 } 3661 }
3783 3662 }
3784 #region Packet Sending 3663
3785 3664 ++updatesThisCall;
3786 const float TIME_DILATION = 1.0f; 3665
3787 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 3666 #region UpdateFlags to packet type conversion
3788 3667
3789 if (terseAgentUpdateBlocks.IsValueCreated) 3668 PrimUpdateFlags updateFlags = update.Flags;
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))
3790 { 3690 {
3791 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3691 canUseCompressed = false;
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);
3802 } 3692 }
3803 3693
3804 if (objectUpdateBlocks.IsValueCreated) 3694 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
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))
3805 { 3708 {
3806 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3709 canUseImproved = false;
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);
3817 } 3710 }
3818 3711 }
3819 if (compressedUpdateBlocks.IsValueCreated) 3712
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)
3820 { 3723 {
3821 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; 3724 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
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);
3832 } 3725 }
3833 3726 else
3834 if (terseUpdateBlocks.IsValueCreated)
3835 { 3727 {
3836 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 3728// if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3837 3729// {
3838 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3730// SceneObjectPart sop = (SceneObjectPart)update.Entity;
3839 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3731// string text = sop.Text;
3840 packet.RegionData.TimeDilation = timeDilation; 3732// if (text.IndexOf("\n") >= 0)
3841 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3733// text = text.Remove(text.IndexOf("\n"));
3842 3734//
3843 for (int i = 0; i < blocks.Count; i++) 3735// if (m_attachmentsSent.Contains(sop.ParentID))
3844 packet.ObjectData[i] = blocks[i]; 3736// {
3845 3737//// m_log.DebugFormat(
3846 OutPacket(packet, ThrottleOutPacketType.Task, true); 3738//// "[CLIENT]: Sending full info about attached prim {0} text {1}",
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// }
3847 } 3758 }
3848 } 3759 }
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);
3849 } 3840 }
3850 3841
3851 #endregion Packet Sending 3842 #endregion Packet Sending