diff options
author | Justin Clark-Casey (justincc) | 2010-12-15 23:11:42 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2010-12-15 23:11:42 +0000 |
commit | 0745d65344a030f598c4b6e522c78fd0e49850d4 (patch) | |
tree | 74f9607f44a20ef25de59aeffd03aa868aee694a /OpenSim/Region/ClientStack | |
parent | Yet more things out of the main Update thread loop and into threadlets. This ... (diff) | |
download | opensim-SC_OLD-0745d65344a030f598c4b6e522c78fd0e49850d4.zip opensim-SC_OLD-0745d65344a030f598c4b6e522c78fd0e49850d4.tar.gz opensim-SC_OLD-0745d65344a030f598c4b6e522c78fd0e49850d4.tar.bz2 opensim-SC_OLD-0745d65344a030f598c4b6e522c78fd0e49850d4.tar.xz |
Put in locks on m_killRecord to replace changed locks on m_entityUpdates.SyncRoot
These locks are necessary to avoid a delete/update race condition for scene objects.
However, since we're now locking on m_killRecord this shouldn't cause delays to m_entityUpdates reprioritization
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 393 |
1 files changed, 200 insertions, 193 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 2a59a0c..3b7328d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -327,7 +327,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
327 | /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an | 327 | /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an |
328 | /// ownerless phantom. | 328 | /// ownerless phantom. |
329 | /// | 329 | /// |
330 | /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock | 330 | /// All manipulation of this set has to occur under a lock |
331 | /// | 331 | /// |
332 | /// </value> | 332 | /// </value> |
333 | protected HashSet<uint> m_killRecord; | 333 | protected HashSet<uint> m_killRecord; |
@@ -1521,7 +1521,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1521 | 1521 | ||
1522 | if (m_scene.GetScenePresence(localID) == null) | 1522 | if (m_scene.GetScenePresence(localID) == null) |
1523 | { | 1523 | { |
1524 | lock (m_entityUpdates.SyncRoot) | 1524 | // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race |
1525 | // condition where a kill can be processed before an out-of-date update for the same object. | ||
1526 | lock (m_killRecord) | ||
1525 | { | 1527 | { |
1526 | m_killRecord.Add(localID); | 1528 | m_killRecord.Add(localID); |
1527 | 1529 | ||
@@ -3558,221 +3560,226 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3558 | if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; | 3560 | if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; |
3559 | int updatesThisCall = 0; | 3561 | int updatesThisCall = 0; |
3560 | 3562 | ||
3561 | EntityUpdate update; | 3563 | // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race |
3562 | while (updatesThisCall < maxUpdates) | 3564 | // condition where a kill can be processed before an out-of-date update for the same object. |
3563 | { | 3565 | lock (m_killRecord) |
3564 | lock (m_entityUpdates.SyncRoot) | 3566 | { |
3565 | if (!m_entityUpdates.TryDequeue(out update)) | 3567 | EntityUpdate update; |
3566 | break; | 3568 | while (updatesThisCall < maxUpdates) |
3567 | 3569 | { | |
3568 | if (update.Entity is SceneObjectPart) | 3570 | lock (m_entityUpdates.SyncRoot) |
3569 | { | 3571 | if (!m_entityUpdates.TryDequeue(out update)) |
3570 | SceneObjectPart part = (SceneObjectPart)update.Entity; | 3572 | break; |
3571 | 3573 | ||
3572 | // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client | 3574 | if (update.Entity is SceneObjectPart) |
3573 | // will never receive an update after a prim kill. Even then, keeping the kill record may be a good | ||
3574 | // safety measure. | ||
3575 | // | ||
3576 | // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update | ||
3577 | // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs | ||
3578 | // updates and kills on different threads with different scheduling strategies, hence this protection. | ||
3579 | // | ||
3580 | // This doesn't appear to apply to child prims - a client will happily ignore these updates | ||
3581 | // after the root prim has been deleted. | ||
3582 | if (m_killRecord.Contains(part.LocalId)) | ||
3583 | { | ||
3584 | // m_log.WarnFormat( | ||
3585 | // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", | ||
3586 | // part.LocalId, Name); | ||
3587 | continue; | ||
3588 | } | ||
3589 | |||
3590 | if (part.ParentGroup.IsAttachment && m_disableFacelights) | ||
3591 | { | 3575 | { |
3592 | if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && | 3576 | SceneObjectPart part = (SceneObjectPart)update.Entity; |
3593 | part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) | 3577 | |
3578 | // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client | ||
3579 | // will never receive an update after a prim kill. Even then, keeping the kill record may be a good | ||
3580 | // safety measure. | ||
3581 | // | ||
3582 | // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update | ||
3583 | // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs | ||
3584 | // updates and kills on different threads with different scheduling strategies, hence this protection. | ||
3585 | // | ||
3586 | // This doesn't appear to apply to child prims - a client will happily ignore these updates | ||
3587 | // after the root prim has been deleted. | ||
3588 | if (m_killRecord.Contains(part.LocalId)) | ||
3594 | { | 3589 | { |
3595 | part.Shape.LightEntry = false; | 3590 | // m_log.WarnFormat( |
3591 | // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", | ||
3592 | // part.LocalId, Name); | ||
3593 | continue; | ||
3594 | } | ||
3595 | |||
3596 | if (part.ParentGroup.IsAttachment && m_disableFacelights) | ||
3597 | { | ||
3598 | if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && | ||
3599 | part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) | ||
3600 | { | ||
3601 | part.Shape.LightEntry = false; | ||
3602 | } | ||
3596 | } | 3603 | } |
3597 | } | 3604 | } |
3598 | } | 3605 | |
3599 | 3606 | ++updatesThisCall; | |
3600 | ++updatesThisCall; | 3607 | |
3601 | 3608 | #region UpdateFlags to packet type conversion | |
3602 | #region UpdateFlags to packet type conversion | 3609 | |
3603 | 3610 | PrimUpdateFlags updateFlags = update.Flags; | |
3604 | PrimUpdateFlags updateFlags = update.Flags; | 3611 | |
3605 | 3612 | bool canUseCompressed = true; | |
3606 | bool canUseCompressed = true; | 3613 | bool canUseImproved = true; |
3607 | bool canUseImproved = true; | 3614 | |
3608 | 3615 | // Compressed object updates only make sense for LL primitives | |
3609 | // Compressed object updates only make sense for LL primitives | 3616 | if (!(update.Entity is SceneObjectPart)) |
3610 | if (!(update.Entity is SceneObjectPart)) | ||
3611 | { | ||
3612 | canUseCompressed = false; | ||
3613 | } | ||
3614 | |||
3615 | if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) | ||
3616 | { | ||
3617 | canUseCompressed = false; | ||
3618 | canUseImproved = false; | ||
3619 | } | ||
3620 | else | ||
3621 | { | ||
3622 | if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || | ||
3623 | updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || | ||
3624 | updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || | ||
3625 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
3626 | { | 3617 | { |
3627 | canUseCompressed = false; | 3618 | canUseCompressed = false; |
3628 | } | 3619 | } |
3629 | 3620 | ||
3630 | if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || | 3621 | if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) |
3631 | updateFlags.HasFlag(PrimUpdateFlags.ParentID) || | ||
3632 | updateFlags.HasFlag(PrimUpdateFlags.Scale) || | ||
3633 | updateFlags.HasFlag(PrimUpdateFlags.PrimData) || | ||
3634 | updateFlags.HasFlag(PrimUpdateFlags.Text) || | ||
3635 | updateFlags.HasFlag(PrimUpdateFlags.NameValue) || | ||
3636 | updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || | ||
3637 | updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || | ||
3638 | updateFlags.HasFlag(PrimUpdateFlags.Sound) || | ||
3639 | updateFlags.HasFlag(PrimUpdateFlags.Particles) || | ||
3640 | updateFlags.HasFlag(PrimUpdateFlags.Material) || | ||
3641 | updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || | ||
3642 | updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || | ||
3643 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
3644 | { | 3622 | { |
3623 | canUseCompressed = false; | ||
3645 | canUseImproved = false; | 3624 | canUseImproved = false; |
3646 | } | 3625 | } |
3647 | } | ||
3648 | |||
3649 | #endregion UpdateFlags to packet type conversion | ||
3650 | |||
3651 | #region Block Construction | ||
3652 | |||
3653 | // TODO: Remove this once we can build compressed updates | ||
3654 | canUseCompressed = false; | ||
3655 | |||
3656 | if (!canUseImproved && !canUseCompressed) | ||
3657 | { | ||
3658 | if (update.Entity is ScenePresence) | ||
3659 | { | ||
3660 | objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); | ||
3661 | } | ||
3662 | else | 3626 | else |
3663 | { | 3627 | { |
3664 | // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) | 3628 | if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || |
3665 | // { | 3629 | updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || |
3666 | // SceneObjectPart sop = (SceneObjectPart)update.Entity; | 3630 | updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || |
3667 | // string text = sop.Text; | 3631 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) |
3668 | // if (text.IndexOf("\n") >= 0) | 3632 | { |
3669 | // text = text.Remove(text.IndexOf("\n")); | 3633 | canUseCompressed = false; |
3670 | // | 3634 | } |
3671 | // if (m_attachmentsSent.Contains(sop.ParentID)) | ||
3672 | // { | ||
3673 | //// m_log.DebugFormat( | ||
3674 | //// "[CLIENT]: Sending full info about attached prim {0} text {1}", | ||
3675 | //// sop.LocalId, text); | ||
3676 | // | ||
3677 | // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); | ||
3678 | // | ||
3679 | // m_attachmentsSent.Add(sop.LocalId); | ||
3680 | // } | ||
3681 | // else | ||
3682 | // { | ||
3683 | // m_log.DebugFormat( | ||
3684 | // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", | ||
3685 | // sop.LocalId, text, sop.ParentID); | ||
3686 | // | ||
3687 | // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); | ||
3688 | // } | ||
3689 | // } | ||
3690 | // else | ||
3691 | // { | ||
3692 | objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); | ||
3693 | // } | ||
3694 | } | ||
3695 | } | ||
3696 | else if (!canUseImproved) | ||
3697 | { | ||
3698 | compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); | ||
3699 | } | ||
3700 | else | ||
3701 | { | ||
3702 | if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) | ||
3703 | // Self updates go into a special list | ||
3704 | terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | ||
3705 | else | ||
3706 | // Everything else goes here | ||
3707 | terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | ||
3708 | } | ||
3709 | |||
3710 | #endregion Block Construction | ||
3711 | } | ||
3712 | |||
3713 | #region Packet Sending | ||
3714 | 3635 | ||
3715 | const float TIME_DILATION = 1.0f; | 3636 | if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || |
3716 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); | 3637 | updateFlags.HasFlag(PrimUpdateFlags.ParentID) || |
3717 | 3638 | updateFlags.HasFlag(PrimUpdateFlags.Scale) || | |
3718 | if (terseAgentUpdateBlocks.IsValueCreated) | 3639 | updateFlags.HasFlag(PrimUpdateFlags.PrimData) || |
3719 | { | 3640 | updateFlags.HasFlag(PrimUpdateFlags.Text) || |
3720 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; | 3641 | updateFlags.HasFlag(PrimUpdateFlags.NameValue) || |
3721 | 3642 | updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || | |
3722 | ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); | 3643 | updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || |
3723 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 3644 | updateFlags.HasFlag(PrimUpdateFlags.Sound) || |
3724 | packet.RegionData.TimeDilation = timeDilation; | 3645 | updateFlags.HasFlag(PrimUpdateFlags.Particles) || |
3725 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | 3646 | updateFlags.HasFlag(PrimUpdateFlags.Material) || |
3726 | 3647 | updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || | |
3727 | for (int i = 0; i < blocks.Count; i++) | 3648 | updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || |
3728 | packet.ObjectData[i] = blocks[i]; | 3649 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) |
3729 | 3650 | { | |
3730 | OutPacket(packet, ThrottleOutPacketType.Unknown, true); | 3651 | canUseImproved = false; |
3731 | } | 3652 | } |
3732 | 3653 | } | |
3733 | if (objectUpdateBlocks.IsValueCreated) | ||
3734 | { | ||
3735 | List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; | ||
3736 | 3654 | ||
3737 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | 3655 | #endregion UpdateFlags to packet type conversion |
3738 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3739 | packet.RegionData.TimeDilation = timeDilation; | ||
3740 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3741 | 3656 | ||
3742 | for (int i = 0; i < blocks.Count; i++) | 3657 | #region Block Construction |
3743 | packet.ObjectData[i] = blocks[i]; | ||
3744 | 3658 | ||
3745 | OutPacket(packet, ThrottleOutPacketType.Task, true); | 3659 | // TODO: Remove this once we can build compressed updates |
3746 | } | 3660 | canUseCompressed = false; |
3747 | 3661 | ||
3748 | if (compressedUpdateBlocks.IsValueCreated) | 3662 | if (!canUseImproved && !canUseCompressed) |
3749 | { | 3663 | { |
3750 | List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; | 3664 | if (update.Entity is ScenePresence) |
3665 | { | ||
3666 | objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); | ||
3667 | } | ||
3668 | else | ||
3669 | { | ||
3670 | // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment) | ||
3671 | // { | ||
3672 | // SceneObjectPart sop = (SceneObjectPart)update.Entity; | ||
3673 | // string text = sop.Text; | ||
3674 | // if (text.IndexOf("\n") >= 0) | ||
3675 | // text = text.Remove(text.IndexOf("\n")); | ||
3676 | // | ||
3677 | // if (m_attachmentsSent.Contains(sop.ParentID)) | ||
3678 | // { | ||
3679 | //// m_log.DebugFormat( | ||
3680 | //// "[CLIENT]: Sending full info about attached prim {0} text {1}", | ||
3681 | //// sop.LocalId, text); | ||
3682 | // | ||
3683 | // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId)); | ||
3684 | // | ||
3685 | // m_attachmentsSent.Add(sop.LocalId); | ||
3686 | // } | ||
3687 | // else | ||
3688 | // { | ||
3689 | // m_log.DebugFormat( | ||
3690 | // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet", | ||
3691 | // sop.LocalId, text, sop.ParentID); | ||
3692 | // | ||
3693 | // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId); | ||
3694 | // } | ||
3695 | // } | ||
3696 | // else | ||
3697 | // { | ||
3698 | objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); | ||
3699 | // } | ||
3700 | } | ||
3701 | } | ||
3702 | else if (!canUseImproved) | ||
3703 | { | ||
3704 | compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); | ||
3705 | } | ||
3706 | else | ||
3707 | { | ||
3708 | if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) | ||
3709 | // Self updates go into a special list | ||
3710 | terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | ||
3711 | else | ||
3712 | // Everything else goes here | ||
3713 | terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | ||
3714 | } | ||
3751 | 3715 | ||
3752 | ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); | 3716 | #endregion Block Construction |
3753 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 3717 | } |
3754 | packet.RegionData.TimeDilation = timeDilation; | ||
3755 | packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; | ||
3756 | 3718 | ||
3757 | for (int i = 0; i < blocks.Count; i++) | 3719 | #region Packet Sending |
3758 | packet.ObjectData[i] = blocks[i]; | 3720 | |
3721 | const float TIME_DILATION = 1.0f; | ||
3722 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); | ||
3759 | 3723 | ||
3760 | OutPacket(packet, ThrottleOutPacketType.Task, true); | 3724 | if (terseAgentUpdateBlocks.IsValueCreated) |
3761 | } | 3725 | { |
3726 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; | ||
3762 | 3727 | ||
3763 | if (terseUpdateBlocks.IsValueCreated) | 3728 | ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); |
3764 | { | 3729 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; |
3765 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; | 3730 | packet.RegionData.TimeDilation = timeDilation; |
3731 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3766 | 3732 | ||
3767 | ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); | 3733 | for (int i = 0; i < blocks.Count; i++) |
3768 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 3734 | packet.ObjectData[i] = blocks[i]; |
3769 | packet.RegionData.TimeDilation = timeDilation; | ||
3770 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3771 | 3735 | ||
3772 | for (int i = 0; i < blocks.Count; i++) | 3736 | OutPacket(packet, ThrottleOutPacketType.Unknown, true); |
3773 | packet.ObjectData[i] = blocks[i]; | 3737 | } |
3774 | 3738 | ||
3775 | OutPacket(packet, ThrottleOutPacketType.Task, true); | 3739 | if (objectUpdateBlocks.IsValueCreated) |
3740 | { | ||
3741 | List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; | ||
3742 | |||
3743 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | ||
3744 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3745 | packet.RegionData.TimeDilation = timeDilation; | ||
3746 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3747 | |||
3748 | for (int i = 0; i < blocks.Count; i++) | ||
3749 | packet.ObjectData[i] = blocks[i]; | ||
3750 | |||
3751 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
3752 | } | ||
3753 | |||
3754 | if (compressedUpdateBlocks.IsValueCreated) | ||
3755 | { | ||
3756 | List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; | ||
3757 | |||
3758 | ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); | ||
3759 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3760 | packet.RegionData.TimeDilation = timeDilation; | ||
3761 | packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; | ||
3762 | |||
3763 | for (int i = 0; i < blocks.Count; i++) | ||
3764 | packet.ObjectData[i] = blocks[i]; | ||
3765 | |||
3766 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
3767 | } | ||
3768 | |||
3769 | if (terseUpdateBlocks.IsValueCreated) | ||
3770 | { | ||
3771 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; | ||
3772 | |||
3773 | ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); | ||
3774 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3775 | packet.RegionData.TimeDilation = timeDilation; | ||
3776 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
3777 | |||
3778 | for (int i = 0; i < blocks.Count; i++) | ||
3779 | packet.ObjectData[i] = blocks[i]; | ||
3780 | |||
3781 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
3782 | } | ||
3776 | } | 3783 | } |
3777 | 3784 | ||
3778 | #endregion Packet Sending | 3785 | #endregion Packet Sending |