diff options
author | UbitUmarov | 2019-02-27 10:07:25 +0000 |
---|---|---|
committer | UbitUmarov | 2019-02-27 10:07:25 +0000 |
commit | bcf05afd64d3b38c66d6d117a51e336a7e98dfc3 (patch) | |
tree | 86e40c3780aa30a1bb2559a30ff4f48d38d02fd3 /OpenSim/Region/ClientStack/Linden | |
parent | avoid packet split on terseupdates (diff) | |
download | opensim-SC-bcf05afd64d3b38c66d6d117a51e336a7e98dfc3.zip opensim-SC-bcf05afd64d3b38c66d6d117a51e336a7e98dfc3.tar.gz opensim-SC-bcf05afd64d3b38c66d6d117a51e336a7e98dfc3.tar.bz2 opensim-SC-bcf05afd64d3b38c66d6d117a51e336a7e98dfc3.tar.xz |
direct encode terseupdates
Diffstat (limited to '')
4 files changed, 207 insertions, 37 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index f28534b..a9edf08 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -4084,6 +4084,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4084 | ResendPrimUpdate(update); | 4084 | ResendPrimUpdate(update); |
4085 | } | 4085 | } |
4086 | 4086 | ||
4087 | static private readonly byte[] terseUpdateHeader = new byte[] { | ||
4088 | Helpers.MSG_RELIABLE, | ||
4089 | 0, 0, 0, 0, // sequence number | ||
4090 | 0, // extra | ||
4091 | 15 // ID (high frequency) | ||
4092 | }; | ||
4093 | |||
4087 | private void ProcessEntityUpdates(int maxUpdatesBytes) | 4094 | private void ProcessEntityUpdates(int maxUpdatesBytes) |
4088 | { | 4095 | { |
4089 | if (!IsActive) | 4096 | if (!IsActive) |
@@ -4377,38 +4384,51 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4377 | { | 4384 | { |
4378 | const int maxNBlocks = (LLUDPServer.MTU - 18) / 63; // no texture entry | 4385 | const int maxNBlocks = (LLUDPServer.MTU - 18) / 63; // no texture entry |
4379 | int blocks = terseAgentUpdates.Count; | 4386 | int blocks = terseAgentUpdates.Count; |
4380 | |||
4381 | ImprovedTerseObjectUpdatePacket packet | ||
4382 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | ||
4383 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4384 | packet.RegionData.TimeDilation = timeDilation; | ||
4385 | |||
4386 | int curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; | 4387 | int curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; |
4387 | List<EntityUpdate> tau = new List<EntityUpdate>(curNBlocks); | 4388 | List<EntityUpdate> tau = new List<EntityUpdate>(curNBlocks); |
4388 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[curNBlocks]; | 4389 | |
4390 | UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); | ||
4391 | |||
4392 | //setup header and regioninfo block | ||
4393 | Array.Copy(terseUpdateHeader, buf.Data, 7); | ||
4394 | Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, buf.Data, 7); | ||
4395 | Utils.UInt16ToBytes(timeDilation, buf.Data, 15); | ||
4396 | buf.Data[17] = (byte)curNBlocks; | ||
4397 | int pos = 18; | ||
4389 | 4398 | ||
4390 | int count = 0; | 4399 | int count = 0; |
4391 | foreach (EntityUpdate eu in terseAgentUpdates) | 4400 | foreach (EntityUpdate eu in terseAgentUpdates) |
4392 | { | 4401 | { |
4393 | packet.ObjectData[count++] = CreateImprovedTerseBlock(eu.Entity); | 4402 | CreateImprovedTerseBlock(eu.Entity, buf.Data, ref pos); |
4394 | tau.Add(eu); | 4403 | tau.Add(eu); |
4404 | ++count; | ||
4395 | --blocks; | 4405 | --blocks; |
4396 | if (count == curNBlocks && blocks > 0) | 4406 | if (count == curNBlocks && blocks > 0) |
4397 | { | 4407 | { |
4398 | OutPacket(packet, ThrottleOutPacketType.Unknown, false, delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }); | 4408 | // we need more packets |
4399 | packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | 4409 | UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); |
4400 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 4410 | Array.Copy(buf.Data, newbuf.Data, 17); // start is the same |
4401 | packet.RegionData.TimeDilation = timeDilation; | 4411 | |
4412 | buf.DataLength = pos; | ||
4413 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown, | ||
4414 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false); | ||
4402 | 4415 | ||
4403 | curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; | 4416 | curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; |
4404 | tau = new List<EntityUpdate>(curNBlocks); | 4417 | tau = new List<EntityUpdate>(curNBlocks); |
4405 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[curNBlocks]; | ||
4406 | count = 0; | 4418 | count = 0; |
4419 | |||
4420 | buf = newbuf; | ||
4421 | buf.Data[17] = (byte)curNBlocks; | ||
4422 | pos = 18; | ||
4407 | } | 4423 | } |
4408 | } | 4424 | } |
4409 | 4425 | ||
4410 | if (tau.Count > 0) | 4426 | if (count > 0) |
4411 | OutPacket(packet, ThrottleOutPacketType.Unknown, false, delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }); | 4427 | { |
4428 | buf.DataLength = pos; | ||
4429 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown, | ||
4430 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false); | ||
4431 | } | ||
4412 | } | 4432 | } |
4413 | 4433 | ||
4414 | if (objectUpdateBlocks != null) | 4434 | if (objectUpdateBlocks != null) |
@@ -4437,38 +4457,51 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4437 | { | 4457 | { |
4438 | const int maxNBlocks = (LLUDPServer.MTU - 18) / 47; // no texture entry | 4458 | const int maxNBlocks = (LLUDPServer.MTU - 18) / 47; // no texture entry |
4439 | int blocks = terseUpdates.Count; | 4459 | int blocks = terseUpdates.Count; |
4440 | |||
4441 | ImprovedTerseObjectUpdatePacket packet = | ||
4442 | (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | ||
4443 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4444 | packet.RegionData.TimeDilation = timeDilation; | ||
4445 | |||
4446 | int curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; | 4460 | int curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; |
4447 | List<EntityUpdate> tau = new List<EntityUpdate>(curNBlocks); | 4461 | List<EntityUpdate> tau = new List<EntityUpdate>(curNBlocks); |
4448 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[curNBlocks]; | 4462 | |
4463 | UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); | ||
4464 | |||
4465 | //setup header and regioninfo block | ||
4466 | Array.Copy(terseUpdateHeader, buf.Data, 7); | ||
4467 | Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, buf.Data, 7); | ||
4468 | Utils.UInt16ToBytes(timeDilation, buf.Data, 15); | ||
4469 | buf.Data[17] = (byte)curNBlocks; | ||
4470 | int pos = 18; | ||
4449 | 4471 | ||
4450 | int count = 0; | 4472 | int count = 0; |
4451 | foreach (EntityUpdate eu in terseUpdates) | 4473 | foreach (EntityUpdate eu in terseUpdates) |
4452 | { | 4474 | { |
4453 | packet.ObjectData[count++] = CreateImprovedTerseBlock(eu.Entity); | 4475 | CreateImprovedTerseBlock(eu.Entity, buf.Data, ref pos); |
4454 | tau.Add(eu); | 4476 | tau.Add(eu); |
4477 | ++count; | ||
4455 | --blocks; | 4478 | --blocks; |
4456 | if (count == curNBlocks && blocks > 0) | 4479 | if (count == curNBlocks && blocks > 0) |
4457 | { | 4480 | { |
4458 | OutPacket(packet, ThrottleOutPacketType.Task, false, delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }); | 4481 | // we need more packets |
4459 | packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | 4482 | UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); |
4460 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 4483 | Array.Copy(buf.Data, newbuf.Data, 17); // start is the same |
4461 | packet.RegionData.TimeDilation = timeDilation; | 4484 | |
4485 | buf.DataLength = pos; | ||
4486 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, | ||
4487 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false); | ||
4462 | 4488 | ||
4463 | curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; | 4489 | curNBlocks = blocks > maxNBlocks ? maxNBlocks : blocks; |
4464 | tau = new List<EntityUpdate>(curNBlocks); | 4490 | tau = new List<EntityUpdate>(curNBlocks); |
4465 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[curNBlocks]; | ||
4466 | count = 0; | 4491 | count = 0; |
4492 | |||
4493 | buf = newbuf; | ||
4494 | buf.Data[17] = (byte)curNBlocks; | ||
4495 | pos = 18; | ||
4467 | } | 4496 | } |
4468 | } | 4497 | } |
4469 | 4498 | ||
4470 | if (tau.Count > 0) | 4499 | if (count > 0) |
4471 | OutPacket(packet, ThrottleOutPacketType.Task, false, delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }); | 4500 | { |
4501 | buf.DataLength = pos; | ||
4502 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, | ||
4503 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false); | ||
4504 | } | ||
4472 | } | 4505 | } |
4473 | 4506 | ||
4474 | if (ObjectAnimationUpdates != null) | 4507 | if (ObjectAnimationUpdates != null) |
@@ -5686,6 +5719,123 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5686 | return block; | 5719 | return block; |
5687 | } | 5720 | } |
5688 | 5721 | ||
5722 | |||
5723 | protected void CreateImprovedTerseBlock(ISceneEntity entity, byte[] data, ref int pos) | ||
5724 | { | ||
5725 | #region ScenePresence/SOP Handling | ||
5726 | |||
5727 | bool avatar = (entity is ScenePresence); | ||
5728 | uint localID = entity.LocalId; | ||
5729 | uint attachPoint; | ||
5730 | Vector4 collisionPlane; | ||
5731 | Vector3 position, velocity, acceleration, angularVelocity; | ||
5732 | Quaternion rotation; | ||
5733 | byte datasize; | ||
5734 | |||
5735 | if (avatar) | ||
5736 | { | ||
5737 | ScenePresence presence = (ScenePresence)entity; | ||
5738 | |||
5739 | position = presence.OffsetPosition; | ||
5740 | velocity = presence.Velocity; | ||
5741 | acceleration = Vector3.Zero; | ||
5742 | rotation = presence.Rotation; | ||
5743 | // tpvs can only see rotations around Z in some cases | ||
5744 | if (!presence.Flying && !presence.IsSatOnObject) | ||
5745 | { | ||
5746 | rotation.X = 0f; | ||
5747 | rotation.Y = 0f; | ||
5748 | } | ||
5749 | rotation.Normalize(); | ||
5750 | angularVelocity = presence.AngularVelocity; | ||
5751 | |||
5752 | // m_log.DebugFormat( | ||
5753 | // "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); | ||
5754 | |||
5755 | attachPoint = presence.State; | ||
5756 | collisionPlane = presence.CollisionPlane; | ||
5757 | |||
5758 | datasize = 60; | ||
5759 | } | ||
5760 | else | ||
5761 | { | ||
5762 | SceneObjectPart part = (SceneObjectPart)entity; | ||
5763 | |||
5764 | attachPoint = part.ParentGroup.AttachmentPoint; | ||
5765 | attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); | ||
5766 | // m_log.DebugFormat( | ||
5767 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", | ||
5768 | // attachPoint, part.Name, part.LocalId, Name); | ||
5769 | |||
5770 | collisionPlane = Vector4.Zero; | ||
5771 | position = part.RelativePosition; | ||
5772 | velocity = part.Velocity; | ||
5773 | acceleration = part.Acceleration; | ||
5774 | angularVelocity = part.AngularVelocity; | ||
5775 | rotation = part.RotationOffset; | ||
5776 | |||
5777 | datasize = 44; | ||
5778 | } | ||
5779 | |||
5780 | #endregion ScenePresence/SOP Handling | ||
5781 | //object block size | ||
5782 | data[pos++] = datasize; | ||
5783 | |||
5784 | // LocalID | ||
5785 | Utils.UIntToBytes(localID, data, pos); | ||
5786 | pos += 4; | ||
5787 | |||
5788 | // Avatar/CollisionPlane | ||
5789 | data[pos++] = (byte)attachPoint; | ||
5790 | if (avatar) | ||
5791 | { | ||
5792 | data[pos++] = 1; | ||
5793 | |||
5794 | if (collisionPlane == Vector4.Zero) | ||
5795 | collisionPlane = Vector4.UnitW; | ||
5796 | //m_log.DebugFormat("CollisionPlane: {0}",collisionPlane); | ||
5797 | collisionPlane.ToBytes(data, pos); | ||
5798 | pos += 16; | ||
5799 | } | ||
5800 | else | ||
5801 | { | ||
5802 | data[pos++] = 0; | ||
5803 | } | ||
5804 | |||
5805 | // Position | ||
5806 | position.ToBytes(data, pos); | ||
5807 | pos += 12; | ||
5808 | |||
5809 | // Velocity | ||
5810 | ClampVectorForUint(ref velocity, 128f); | ||
5811 | Utils.FloatToUInt16Bytes(velocity.X, 128.0f, data, pos); pos += 2; | ||
5812 | Utils.FloatToUInt16Bytes(velocity.Y, 128.0f, data, pos); pos += 2; | ||
5813 | Utils.FloatToUInt16Bytes(velocity.Z, 128.0f, data, pos); pos += 2; | ||
5814 | |||
5815 | // Acceleration | ||
5816 | ClampVectorForUint(ref acceleration, 64f); | ||
5817 | Utils.FloatToUInt16Bytes(acceleration.X, 64.0f, data, pos); pos += 2; | ||
5818 | Utils.FloatToUInt16Bytes(acceleration.Y, 64.0f, data, pos); pos += 2; | ||
5819 | Utils.FloatToUInt16Bytes(acceleration.Z, 64.0f, data, pos); pos += 2; | ||
5820 | |||
5821 | // Rotation | ||
5822 | Utils.FloatToUInt16Bytes(rotation.X, 1.0f, data, pos); pos += 2; | ||
5823 | Utils.FloatToUInt16Bytes(rotation.Y, 1.0f, data, pos); pos += 2; | ||
5824 | Utils.FloatToUInt16Bytes(rotation.Z, 1.0f, data, pos); pos += 2; | ||
5825 | Utils.FloatToUInt16Bytes(rotation.W, 1.0f, data, pos); pos += 2; | ||
5826 | |||
5827 | // Angular Velocity | ||
5828 | ClampVectorForUint(ref angularVelocity, 64f); | ||
5829 | Utils.FloatToUInt16Bytes(angularVelocity.X, 64.0f, data, pos); pos += 2; | ||
5830 | Utils.FloatToUInt16Bytes(angularVelocity.Y, 64.0f, data, pos); pos += 2; | ||
5831 | Utils.FloatToUInt16Bytes(angularVelocity.Z, 64.0f, data, pos); pos += 2; | ||
5832 | |||
5833 | // texture entry block size | ||
5834 | data[pos++] = 0; | ||
5835 | data[pos++] = 0; | ||
5836 | // total size 63 or 47 | ||
5837 | } | ||
5838 | |||
5689 | protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) | 5839 | protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) |
5690 | { | 5840 | { |
5691 | Vector3 offsetPosition = data.OffsetPosition; | 5841 | Vector3 offsetPosition = data.OffsetPosition; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index fca7943..d0d2152 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -575,22 +575,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
575 | { | 575 | { |
576 | DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; | 576 | DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; |
577 | 577 | ||
578 | if (m_deliverPackets == false) | 578 | if (forceQueue || m_deliverPackets == false) |
579 | { | 579 | { |
580 | queue.Enqueue(packet, highPriority); | 580 | queue.Enqueue(packet, highPriority); |
581 | return true; | 581 | return true; |
582 | } | 582 | } |
583 | 583 | ||
584 | TokenBucket bucket = m_throttleCategories[category]; | 584 | // need to enqueue if queue is not empty |
585 | |||
586 | // Don't send this packet if queue is not empty | ||
587 | if (queue.Count > 0 || m_nextPackets[category] != null) | 585 | if (queue.Count > 0 || m_nextPackets[category] != null) |
588 | { | 586 | { |
589 | queue.Enqueue(packet, highPriority); | 587 | queue.Enqueue(packet, highPriority); |
590 | return true; | 588 | return true; |
591 | } | 589 | } |
592 | 590 | ||
593 | if (!forceQueue && bucket.CheckTokens(packet.Buffer.DataLength)) | 591 | // check bandwidth |
592 | TokenBucket bucket = m_throttleCategories[category]; | ||
593 | if (bucket.CheckTokens(packet.Buffer.DataLength)) | ||
594 | { | 594 | { |
595 | // enough tokens so it can be sent imediatly by caller | 595 | // enough tokens so it can be sent imediatly by caller |
596 | bucket.RemoveTokens(packet.Buffer.DataLength); | 596 | bucket.RemoveTokens(packet.Buffer.DataLength); |
@@ -608,7 +608,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
608 | // We don't have a token bucket for this category, so it will not be queued | 608 | // We don't have a token bucket for this category, so it will not be queued |
609 | return false; | 609 | return false; |
610 | } | 610 | } |
611 | |||
612 | } | 611 | } |
613 | 612 | ||
614 | /// <summary> | 613 | /// <summary> |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index d324623..f12b3b9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -934,6 +934,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
934 | #endregion Queue or Send | 934 | #endregion Queue or Send |
935 | } | 935 | } |
936 | 936 | ||
937 | public void SendUDPPacket( | ||
938 | LLUDPClient udpClient, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method, bool forcequeue) | ||
939 | { | ||
940 | bool highPriority = false; | ||
941 | |||
942 | if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0) | ||
943 | { | ||
944 | category = (ThrottleOutPacketType)((int)category & 127); | ||
945 | highPriority = true; | ||
946 | } | ||
947 | |||
948 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); | ||
949 | |||
950 | // If we were not provided a method for handling unacked, use the UDPServer default method | ||
951 | if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) | ||
952 | outgoingPacket.UnackedMethod = ((method == null) ? delegate (OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); | ||
953 | |||
954 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forcequeue, highPriority)) | ||
955 | SendPacketFinal(outgoingPacket); | ||
956 | } | ||
957 | |||
937 | public void SendAcks(LLUDPClient udpClient) | 958 | public void SendAcks(LLUDPClient udpClient) |
938 | { | 959 | { |
939 | uint ack; | 960 | uint ack; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 6f346d3..49aca3c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -489,7 +489,7 @@ namespace OpenMetaverse | |||
489 | public void SyncSend(UDPPacketBuffer buf) | 489 | public void SyncSend(UDPPacketBuffer buf) |
490 | { | 490 | { |
491 | if(buf.RemoteEndPoint == null) | 491 | if(buf.RemoteEndPoint == null) |
492 | return; // was already expired | 492 | return; // already expired |
493 | try | 493 | try |
494 | { | 494 | { |
495 | m_udpSocket.SendTo( | 495 | m_udpSocket.SendTo( |