aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs687
1 files changed, 390 insertions, 297 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 929f282..6a6bd12 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
155 public event RequestTaskInventory OnRequestTaskInventory; 155 public event RequestTaskInventory OnRequestTaskInventory;
156 public event UpdateInventoryItem OnUpdateInventoryItem; 156 public event UpdateInventoryItem OnUpdateInventoryItem;
157 public event CopyInventoryItem OnCopyInventoryItem; 157 public event CopyInventoryItem OnCopyInventoryItem;
158 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
158 public event MoveInventoryItem OnMoveInventoryItem; 159 public event MoveInventoryItem OnMoveInventoryItem;
159 public event RemoveInventoryItem OnRemoveInventoryItem; 160 public event RemoveInventoryItem OnRemoveInventoryItem;
160 public event RemoveInventoryFolder OnRemoveInventoryFolder; 161 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -327,7 +328,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
327 /// 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
328 /// ownerless phantom. 329 /// ownerless phantom.
329 /// 330 ///
330 /// 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
331 /// 332 ///
332 /// </value> 333 /// </value>
333 protected HashSet<uint> m_killRecord; 334 protected HashSet<uint> m_killRecord;
@@ -335,6 +336,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
335// protected HashSet<uint> m_attachmentsSent; 336// protected HashSet<uint> m_attachmentsSent;
336 337
337 private int m_moneyBalance; 338 private int m_moneyBalance;
339 private bool m_deliverPackets = true;
338 private int m_animationSequenceNumber = 1; 340 private int m_animationSequenceNumber = 1;
339 private bool m_SendLogoutPacketWhenClosing = true; 341 private bool m_SendLogoutPacketWhenClosing = true;
340 private AgentUpdateArgs lastarg; 342 private AgentUpdateArgs lastarg;
@@ -377,6 +379,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
377 get { return m_startpos; } 379 get { return m_startpos; }
378 set { m_startpos = value; } 380 set { m_startpos = value; }
379 } 381 }
382 public bool DeliverPackets
383 {
384 get { return m_deliverPackets; }
385 set {
386 m_deliverPackets = value;
387 m_udpClient.m_deliverPackets = value;
388 }
389 }
380 public UUID AgentId { get { return m_agentId; } } 390 public UUID AgentId { get { return m_agentId; } }
381 public UUID ActiveGroupId { get { return m_activeGroupID; } } 391 public UUID ActiveGroupId { get { return m_activeGroupID; } }
382 public string ActiveGroupName { get { return m_activeGroupName; } } 392 public string ActiveGroupName { get { return m_activeGroupName; } }
@@ -475,18 +485,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
475 485
476 #region Client Methods 486 #region Client Methods
477 487
488
478 /// <summary> 489 /// <summary>
479 /// Shut down the client view 490 /// Shut down the client view
480 /// </summary> 491 /// </summary>
481 public void Close() 492 public void Close()
482 { 493 {
494 Close(true);
495 }
496
497 /// <summary>
498 /// Shut down the client view
499 /// </summary>
500 public void Close(bool sendStop)
501 {
483 m_log.DebugFormat( 502 m_log.DebugFormat(
484 "[CLIENT]: Close has been called for {0} attached to scene {1}", 503 "[CLIENT]: Close has been called for {0} attached to scene {1}",
485 Name, m_scene.RegionInfo.RegionName); 504 Name, m_scene.RegionInfo.RegionName);
486 505
487 // Send the STOP packet 506 if (sendStop)
488 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 507 {
489 OutPacket(disable, ThrottleOutPacketType.Unknown); 508 // Send the STOP packet
509 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
510 OutPacket(disable, ThrottleOutPacketType.Unknown);
511 }
490 512
491 IsActive = false; 513 IsActive = false;
492 514
@@ -767,7 +789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
767 reply.ChatData.OwnerID = fromAgentID; 789 reply.ChatData.OwnerID = fromAgentID;
768 reply.ChatData.SourceID = fromAgentID; 790 reply.ChatData.SourceID = fromAgentID;
769 791
770 OutPacket(reply, ThrottleOutPacketType.Task); 792 OutPacket(reply, ThrottleOutPacketType.Unknown);
771 } 793 }
772 794
773 /// <summary> 795 /// <summary>
@@ -1053,6 +1075,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1053 public virtual void SendLayerData(float[] map) 1075 public virtual void SendLayerData(float[] map)
1054 { 1076 {
1055 Util.FireAndForget(DoSendLayerData, map); 1077 Util.FireAndForget(DoSendLayerData, map);
1078
1079 // Send it sync, and async. It's not that much data
1080 // and it improves user experience just so much!
1081 DoSendLayerData(map);
1056 } 1082 }
1057 1083
1058 /// <summary> 1084 /// <summary>
@@ -1065,16 +1091,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1065 1091
1066 try 1092 try
1067 { 1093 {
1068 //for (int y = 0; y < 16; y++) 1094 for (int y = 0; y < 16; y++)
1069 //{ 1095 {
1070 // for (int x = 0; x < 16; x++) 1096 for (int x = 0; x < 16; x+=4)
1071 // { 1097 {
1072 // SendLayerData(x, y, map); 1098 SendLayerPacket(x, y, map);
1073 // } 1099 }
1074 //} 1100 }
1075
1076 // Send LayerData in a spiral pattern. Fun!
1077 SendLayerTopRight(map, 0, 0, 15, 15);
1078 } 1101 }
1079 catch (Exception e) 1102 catch (Exception e)
1080 { 1103 {
@@ -1082,51 +1105,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1082 } 1105 }
1083 } 1106 }
1084 1107
1085 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1086 {
1087 // Row
1088 for (int i = x1; i <= x2; i++)
1089 SendLayerData(i, y1, map);
1090
1091 // Column
1092 for (int j = y1 + 1; j <= y2; j++)
1093 SendLayerData(x2, j, map);
1094
1095 if (x2 - x1 > 0)
1096 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1097 }
1098
1099 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1100 {
1101 // Row in reverse
1102 for (int i = x2; i >= x1; i--)
1103 SendLayerData(i, y2, map);
1104
1105 // Column in reverse
1106 for (int j = y2 - 1; j >= y1; j--)
1107 SendLayerData(x1, j, map);
1108
1109 if (x2 - x1 > 0)
1110 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1111 }
1112
1113 /// <summary> 1108 /// <summary>
1114 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1109 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1115 /// </summary> 1110 /// </summary>
1116 /// <param name="map">heightmap</param> 1111 /// <param name="map">heightmap</param>
1117 /// <param name="px">X coordinate for patches 0..12</param> 1112 /// <param name="px">X coordinate for patches 0..12</param>
1118 /// <param name="py">Y coordinate for patches 0..15</param> 1113 /// <param name="py">Y coordinate for patches 0..15</param>
1119 // private void SendLayerPacket(float[] map, int y, int x) 1114 private void SendLayerPacket(int x, int y, float[] map)
1120 // { 1115 {
1121 // int[] patches = new int[4]; 1116 int[] patches = new int[4];
1122 // patches[0] = x + 0 + y * 16; 1117 patches[0] = x + 0 + y * 16;
1123 // patches[1] = x + 1 + y * 16; 1118 patches[1] = x + 1 + y * 16;
1124 // patches[2] = x + 2 + y * 16; 1119 patches[2] = x + 2 + y * 16;
1125 // patches[3] = x + 3 + y * 16; 1120 patches[3] = x + 3 + y * 16;
1126 1121
1127 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1122 float[] heightmap = (map.Length == 65536) ?
1128 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1123 map :
1129 // } 1124 LLHeightFieldMoronize(map);
1125
1126 try
1127 {
1128 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1129 OutPacket(layerpack, ThrottleOutPacketType.Land);
1130 }
1131 catch
1132 {
1133 for (int px = x ; px < x + 4 ; px++)
1134 SendLayerData(px, y, map);
1135 }
1136 }
1130 1137
1131 /// <summary> 1138 /// <summary>
1132 /// Sends a specified patch to a client 1139 /// Sends a specified patch to a client
@@ -1146,7 +1153,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1153 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1147 layerpack.Header.Reliable = true; 1154 layerpack.Header.Reliable = true;
1148 1155
1149 OutPacket(layerpack, ThrottleOutPacketType.Land); 1156 OutPacket(layerpack, ThrottleOutPacketType.Task);
1150 } 1157 }
1151 catch (Exception e) 1158 catch (Exception e)
1152 { 1159 {
@@ -1507,37 +1514,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1507 OutPacket(pc, ThrottleOutPacketType.Unknown); 1514 OutPacket(pc, ThrottleOutPacketType.Unknown);
1508 } 1515 }
1509 1516
1510 public void SendKillObject(ulong regionHandle, uint localID) 1517 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1511 { 1518 {
1512// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1519// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1513 1520
1514 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1521 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1515 // TODO: don't create new blocks if recycling an old packet 1522 // TODO: don't create new blocks if recycling an old packet
1516 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; 1523 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1517 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); 1524 for (int i = 0 ; i < localIDs.Count ; i++ )
1518 kill.ObjectData[0].ID = localID; 1525 {
1526 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1527 kill.ObjectData[i].ID = localIDs[i];
1528 }
1519 kill.Header.Reliable = true; 1529 kill.Header.Reliable = true;
1520 kill.Header.Zerocoded = true; 1530 kill.Header.Zerocoded = true;
1521 1531
1522 if (m_scene.GetScenePresence(localID) == null) 1532 lock (m_killRecord)
1523 { 1533 {
1524 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 1534 if (localIDs.Count == 1)
1525 // condition where a kill can be processed before an out-of-date update for the same object.
1526 lock (m_killRecord)
1527 { 1535 {
1528 m_killRecord.Add(localID); 1536 if (m_scene.GetScenePresence(localIDs[0]) != null)
1529 1537 {
1530 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1538 OutPacket(kill, ThrottleOutPacketType.State);
1531 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1539 return;
1532 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1540 }
1533 // scene objects in a viewer until that viewer is relogged in. 1541 m_killRecord.Add(localIDs[0]);
1534 OutPacket(kill, ThrottleOutPacketType.Task); 1542 }
1543 else
1544 {
1545 lock (m_entityUpdates.SyncRoot)
1546 {
1547 foreach (uint localID in localIDs)
1548 m_killRecord.Add(localID);
1549 }
1535 } 1550 }
1536 } 1551 }
1537 else 1552
1538 { 1553 // The throttle queue used here must match that being used for
1539 OutPacket(kill, ThrottleOutPacketType.State); 1554 // updates. Otherwise, there is a chance that a kill packet put
1540 } 1555 // on a separate queue will be sent to the client before an
1556 // existing update packet on another queue. Receiving updates
1557 // after kills results in unowned and undeletable
1558 // scene objects in a viewer until that viewer is relogged in.
1559 OutPacket(kill, ThrottleOutPacketType.Task);
1541 } 1560 }
1542 1561
1543 /// <summary> 1562 /// <summary>
@@ -2250,6 +2269,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2250 OutPacket(sound, ThrottleOutPacketType.Task); 2269 OutPacket(sound, ThrottleOutPacketType.Task);
2251 } 2270 }
2252 2271
2272 public void SendTransferAbort(TransferRequestPacket transferRequest)
2273 {
2274 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2275 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2276 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2277 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2278 OutPacket(abort, ThrottleOutPacketType.Task);
2279 }
2280
2253 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2281 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2254 { 2282 {
2255 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2283 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -3551,6 +3579,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3551 /// </summary> 3579 /// </summary>
3552 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3580 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3553 { 3581 {
3582 if (entity is SceneObjectPart)
3583 {
3584 SceneObjectPart e = (SceneObjectPart)entity;
3585 SceneObjectGroup g = e.ParentGroup;
3586 if (g.RootPart.Shape.State > 30) // HUD
3587 if (g.OwnerID != AgentId)
3588 return; // Don't send updates for other people's HUDs
3589 }
3590
3554 double priority = m_prioritizer.GetUpdatePriority(this, entity); 3591 double priority = m_prioritizer.GetUpdatePriority(this, entity);
3555 3592
3556 lock (m_entityUpdates.SyncRoot) 3593 lock (m_entityUpdates.SyncRoot)
@@ -3567,226 +3604,252 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3567 if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; 3604 if (maxUpdates <= 0) maxUpdates = Int32.MaxValue;
3568 int updatesThisCall = 0; 3605 int updatesThisCall = 0;
3569 3606
3570 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3607 EntityUpdate update;
3571 // condition where a kill can be processed before an out-of-date update for the same object. 3608 while (updatesThisCall < maxUpdates)
3572 lock (m_killRecord) 3609 {
3573 { 3610 lock (m_entityUpdates.SyncRoot)
3574 EntityUpdate update; 3611 if (!m_entityUpdates.TryDequeue(out update))
3575 while (updatesThisCall < maxUpdates) 3612 break;
3576 { 3613
3577 lock (m_entityUpdates.SyncRoot) 3614 if (update.Entity is SceneObjectPart)
3578 if (!m_entityUpdates.TryDequeue(out update)) 3615 {
3579 break; 3616 SceneObjectPart part = (SceneObjectPart)update.Entity;
3580 3617
3581 if (update.Entity is SceneObjectPart) 3618 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3619 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3620 // safety measure.
3621 //
3622 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3623 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3624 // updates and kills on different threads with different scheduling strategies, hence this protection.
3625 //
3626 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3627 // after the root prim has been deleted.
3628 lock (m_killRecord)
3582 { 3629 {
3583 SceneObjectPart part = (SceneObjectPart)update.Entity;
3584
3585 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3586 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3587 // safety measure.
3588 //
3589 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3590 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3591 // updates and kills on different threads with different scheduling strategies, hence this protection.
3592 //
3593 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3594 // after the root prim has been deleted.
3595 if (m_killRecord.Contains(part.LocalId)) 3630 if (m_killRecord.Contains(part.LocalId))
3596 {
3597 // m_log.WarnFormat(
3598 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
3599 // part.LocalId, Name);
3600 continue; 3631 continue;
3601 } 3632 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3602 3633 continue;
3603 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3634 }
3635
3636 if (part.ParentGroup.IsDeleted)
3637 continue;
3638
3639 if (part.ParentGroup.IsAttachment)
3640 { // Someone else's HUD, why are we getting these?
3641 if (part.ParentGroup.OwnerID != AgentId &&
3642 part.ParentGroup.RootPart.Shape.State >= 30)
3643 continue;
3644 ScenePresence sp;
3645 // Owner is not in the sim, don't update it to
3646 // anyone
3647 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3648 continue;
3649
3650 List<SceneObjectGroup> atts = sp.Attachments;
3651 bool found = false;
3652 foreach (SceneObjectGroup att in atts)
3604 { 3653 {
3605 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3654 if (att == part.ParentGroup)
3606 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3607 { 3655 {
3608 part.Shape.LightEntry = false; 3656 found = true;
3657 break;
3609 } 3658 }
3610 } 3659 }
3660
3661 // It's an attachment of a valid avatar, but
3662 // doesn't seem to be attached, skip
3663 if (!found)
3664 continue;
3611 } 3665 }
3612 3666
3613 ++updatesThisCall; 3667 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3614
3615 #region UpdateFlags to packet type conversion
3616
3617 PrimUpdateFlags updateFlags = update.Flags;
3618
3619 bool canUseCompressed = true;
3620 bool canUseImproved = true;
3621
3622 // Compressed object updates only make sense for LL primitives
3623 if (!(update.Entity is SceneObjectPart))
3624 { 3668 {
3625 canUseCompressed = false; 3669 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3670 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3671 {
3672 part.Shape.LightEntry = false;
3673 }
3626 } 3674 }
3627 3675 }
3628 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3676
3677 ++updatesThisCall;
3678
3679 #region UpdateFlags to packet type conversion
3680
3681 PrimUpdateFlags updateFlags = update.Flags;
3682
3683 bool canUseCompressed = true;
3684 bool canUseImproved = true;
3685
3686 // Compressed object updates only make sense for LL primitives
3687 if (!(update.Entity is SceneObjectPart))
3688 {
3689 canUseCompressed = false;
3690 }
3691
3692 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3693 {
3694 canUseCompressed = false;
3695 canUseImproved = false;
3696 }
3697 else
3698 {
3699 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3700 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3701 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3702 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3629 { 3703 {
3630 canUseCompressed = false; 3704 canUseCompressed = false;
3705 }
3706
3707 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3708 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3709 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3710 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3711 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3712 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3713 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3714 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3715 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3716 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3717 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3718 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3719 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3720 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3721 {
3631 canUseImproved = false; 3722 canUseImproved = false;
3632 } 3723 }
3724 }
3725
3726 #endregion UpdateFlags to packet type conversion
3727
3728 #region Block Construction
3729
3730 // TODO: Remove this once we can build compressed updates
3731 canUseCompressed = false;
3732
3733 if (!canUseImproved && !canUseCompressed)
3734 {
3735 if (update.Entity is ScenePresence)
3736 {
3737 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3738 }
3633 else 3739 else
3634 { 3740 {
3635 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3741// if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3636 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || 3742// {
3637 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || 3743// SceneObjectPart sop = (SceneObjectPart)update.Entity;
3638 updateFlags.HasFlag(PrimUpdateFlags.Joint)) 3744// string text = sop.Text;
3639 { 3745// if (text.IndexOf("\n") >= 0)
3640 canUseCompressed = false; 3746// text = text.Remove(text.IndexOf("\n"));
3641 } 3747//
3642 3748// if (m_attachmentsSent.Contains(sop.ParentID))
3643 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || 3749// {
3644 updateFlags.HasFlag(PrimUpdateFlags.ParentID) || 3750//// m_log.DebugFormat(
3645 updateFlags.HasFlag(PrimUpdateFlags.Scale) || 3751//// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3646 updateFlags.HasFlag(PrimUpdateFlags.PrimData) || 3752//// sop.LocalId, text);
3647 updateFlags.HasFlag(PrimUpdateFlags.Text) || 3753//
3648 updateFlags.HasFlag(PrimUpdateFlags.NameValue) || 3754// objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3649 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || 3755//
3650 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || 3756// m_attachmentsSent.Add(sop.LocalId);
3651 updateFlags.HasFlag(PrimUpdateFlags.Sound) || 3757// }
3652 updateFlags.HasFlag(PrimUpdateFlags.Particles) || 3758// else
3653 updateFlags.HasFlag(PrimUpdateFlags.Material) || 3759// {
3654 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || 3760// m_log.DebugFormat(
3655 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || 3761// "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3656 updateFlags.HasFlag(PrimUpdateFlags.Joint)) 3762// sop.LocalId, text, sop.ParentID);
3657 { 3763//
3658 canUseImproved = false; 3764// m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3659 } 3765// }
3766// }
3767// else
3768// {
3769 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3770// }
3660 } 3771 }
3772 }
3773 else if (!canUseImproved)
3774 {
3775 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3776 }
3777 else
3778 {
3779 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3780 // Self updates go into a special list
3781 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3782 else
3783 // Everything else goes here
3784 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3785 }
3786
3787 #endregion Block Construction
3788 }
3789
3790 #region Packet Sending
3661 3791
3662 #endregion UpdateFlags to packet type conversion 3792 const float TIME_DILATION = 1.0f;
3793 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
3794
3795 if (terseAgentUpdateBlocks.IsValueCreated)
3796 {
3797 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3798
3799 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3800 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3801 packet.RegionData.TimeDilation = timeDilation;
3802 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3803
3804 for (int i = 0; i < blocks.Count; i++)
3805 packet.ObjectData[i] = blocks[i];
3806
3807 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3808 }
3809
3810 if (objectUpdateBlocks.IsValueCreated)
3811 {
3812 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3663 3813
3664 #region Block Construction 3814 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3815 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3816 packet.RegionData.TimeDilation = timeDilation;
3817 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3665 3818
3666 // TODO: Remove this once we can build compressed updates 3819 for (int i = 0; i < blocks.Count; i++)
3667 canUseCompressed = false; 3820 packet.ObjectData[i] = blocks[i];
3668 3821
3669 if (!canUseImproved && !canUseCompressed) 3822 OutPacket(packet, ThrottleOutPacketType.Task, true);
3670 { 3823 }
3671 if (update.Entity is ScenePresence)
3672 {
3673 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3674 }
3675 else
3676 {
3677 // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3678 // {
3679 // SceneObjectPart sop = (SceneObjectPart)update.Entity;
3680 // string text = sop.Text;
3681 // if (text.IndexOf("\n") >= 0)
3682 // text = text.Remove(text.IndexOf("\n"));
3683 //
3684 // if (m_attachmentsSent.Contains(sop.ParentID))
3685 // {
3686 //// m_log.DebugFormat(
3687 //// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3688 //// sop.LocalId, text);
3689 //
3690 // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3691 //
3692 // m_attachmentsSent.Add(sop.LocalId);
3693 // }
3694 // else
3695 // {
3696 // m_log.DebugFormat(
3697 // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3698 // sop.LocalId, text, sop.ParentID);
3699 //
3700 // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3701 // }
3702 // }
3703 // else
3704 // {
3705 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3706 // }
3707 }
3708 }
3709 else if (!canUseImproved)
3710 {
3711 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3712 }
3713 else
3714 {
3715 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3716 // Self updates go into a special list
3717 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3718 else
3719 // Everything else goes here
3720 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3721 }
3722 3824
3723 #endregion Block Construction 3825 if (compressedUpdateBlocks.IsValueCreated)
3724 } 3826 {
3827 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3725 3828
3726 #region Packet Sending 3829 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3727 3830 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3728 const float TIME_DILATION = 1.0f; 3831 packet.RegionData.TimeDilation = timeDilation;
3729 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 3832 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3730 3833
3731 if (terseAgentUpdateBlocks.IsValueCreated) 3834 for (int i = 0; i < blocks.Count; i++)
3732 { 3835 packet.ObjectData[i] = blocks[i];
3733 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3734 3836
3735 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3837 OutPacket(packet, ThrottleOutPacketType.Task, true);
3736 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3838 }
3737 packet.RegionData.TimeDilation = timeDilation;
3738 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3739 3839
3740 for (int i = 0; i < blocks.Count; i++) 3840 if (terseUpdateBlocks.IsValueCreated)
3741 packet.ObjectData[i] = blocks[i]; 3841 {
3842 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3742 3843
3743 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 3844 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3744 } 3845 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3846 packet.RegionData.TimeDilation = timeDilation;
3847 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3745 3848
3746 if (objectUpdateBlocks.IsValueCreated) 3849 for (int i = 0; i < blocks.Count; i++)
3747 { 3850 packet.ObjectData[i] = blocks[i];
3748 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3851
3749 3852 OutPacket(packet, ThrottleOutPacketType.Task, true);
3750 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3751 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3752 packet.RegionData.TimeDilation = timeDilation;
3753 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3754
3755 for (int i = 0; i < blocks.Count; i++)
3756 packet.ObjectData[i] = blocks[i];
3757
3758 OutPacket(packet, ThrottleOutPacketType.Task, true);
3759 }
3760
3761 if (compressedUpdateBlocks.IsValueCreated)
3762 {
3763 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3764
3765 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3766 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3767 packet.RegionData.TimeDilation = timeDilation;
3768 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3769
3770 for (int i = 0; i < blocks.Count; i++)
3771 packet.ObjectData[i] = blocks[i];
3772
3773 OutPacket(packet, ThrottleOutPacketType.Task, true);
3774 }
3775
3776 if (terseUpdateBlocks.IsValueCreated)
3777 {
3778 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3779
3780 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3781 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3782 packet.RegionData.TimeDilation = timeDilation;
3783 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3784
3785 for (int i = 0; i < blocks.Count; i++)
3786 packet.ObjectData[i] = blocks[i];
3787
3788 OutPacket(packet, ThrottleOutPacketType.Task, true);
3789 }
3790 } 3853 }
3791 3854
3792 #endregion Packet Sending 3855 #endregion Packet Sending
@@ -4052,6 +4115,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4052 { 4115 {
4053 m_propertiesPacketTimer.Stop(); 4116 m_propertiesPacketTimer.Stop();
4054 4117
4118 if (m_propertiesBlocks.Count == 0)
4119 return;
4120
4055 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; 4121 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count];
4056 4122
4057 int index = 0; 4123 int index = 0;
@@ -4443,14 +4509,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4443 4509
4444 if (notifyCount > 0) 4510 if (notifyCount > 0)
4445 { 4511 {
4446 if (notifyCount > 32) 4512// if (notifyCount > 32)
4447 { 4513// {
4448 m_log.InfoFormat( 4514// m_log.InfoFormat(
4449 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4515// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4450 + " - a developer might want to investigate whether this is a hard limit", 32); 4516// + " - a developer might want to investigate whether this is a hard limit", 32);
4451 4517//
4452 notifyCount = 32; 4518// notifyCount = 32;
4453 } 4519// }
4454 4520
4455 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4521 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4456 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4522 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4958,6 +5024,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4958 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5024 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
4959 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5025 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
4960 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5026 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5027 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
4961 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5028 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
4962 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5029 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
4963 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5030 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5057,6 +5124,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5057 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5124 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5058 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5125 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5059 (x.ControlFlags != lastarg.ControlFlags) || 5126 (x.ControlFlags != lastarg.ControlFlags) ||
5127 (x.ControlFlags != 0) ||
5060 (x.Far != lastarg.Far) || 5128 (x.Far != lastarg.Far) ||
5061 (x.Flags != lastarg.Flags) || 5129 (x.Flags != lastarg.Flags) ||
5062 (x.State != lastarg.State) || 5130 (x.State != lastarg.State) ||
@@ -5430,7 +5498,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5430 args.Channel = ch; 5498 args.Channel = ch;
5431 args.From = String.Empty; 5499 args.From = String.Empty;
5432 args.Message = Utils.BytesToString(msg); 5500 args.Message = Utils.BytesToString(msg);
5433 args.Type = ChatTypeEnum.Shout; 5501 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5434 args.Position = new Vector3(); 5502 args.Position = new Vector3();
5435 args.Scene = Scene; 5503 args.Scene = Scene;
5436 args.Sender = this; 5504 args.Sender = this;
@@ -9474,6 +9542,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9474 { 9542 {
9475 return true; 9543 return true;
9476 } 9544 }
9545
9546 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9547 {
9548 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9549
9550 #region Packet Session and User Check
9551 if (m_checkPackets)
9552 {
9553 if (packet.AgentData.SessionID != SessionId ||
9554 packet.AgentData.AgentID != AgentId)
9555 return true;
9556 }
9557 #endregion
9558 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9559 List<InventoryItemBase> items = new List<InventoryItemBase>();
9560 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9561 {
9562 InventoryItemBase b = new InventoryItemBase();
9563 b.ID = n.OldItemID;
9564 b.Folder = n.OldFolderID;
9565 items.Add(b);
9566 }
9567
9568 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9569 if (handlerMoveItemsAndLeaveCopy != null)
9570 {
9571 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9572 }
9573
9574 return true;
9575 }
9477 9576
9478 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9577 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9479 { 9578 {
@@ -10472,11 +10571,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10472 10571
10473 StartLure handlerStartLure = OnStartLure; 10572 StartLure handlerStartLure = OnStartLure;
10474 if (handlerStartLure != null) 10573 if (handlerStartLure != null)
10475 handlerStartLure(startLureRequest.Info.LureType, 10574 {
10476 Utils.BytesToString( 10575 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10477 startLureRequest.Info.Message), 10576 {
10478 startLureRequest.TargetData[0].TargetID, 10577 handlerStartLure(startLureRequest.Info.LureType,
10479 this); 10578 Utils.BytesToString(
10579 startLureRequest.Info.Message),
10580 startLureRequest.TargetData[i].TargetID,
10581 this);
10582 }
10583 }
10480 return true; 10584 return true;
10481 } 10585 }
10482 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 10586 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -10971,7 +11075,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10971 { 11075 {
10972 // It's a ghost! tell the client to delete it from view. 11076 // It's a ghost! tell the client to delete it from view.
10973 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 11077 simClient.SendKillObject(Scene.RegionInfo.RegionHandle,
10974 localId); 11078 new List<uint>() { localId });
10975 } 11079 }
10976 else 11080 else
10977 { 11081 {
@@ -11344,22 +11448,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11344 /// <param name="Pack">OpenMetaverse.packet</param> 11448 /// <param name="Pack">OpenMetaverse.packet</param>
11345 public void ProcessInPacket(Packet packet) 11449 public void ProcessInPacket(Packet packet)
11346 { 11450 {
11347 if (m_debugPacketLevel > 0) 11451 if (m_debugPacketLevel >= 255)
11348 { 11452 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11349 bool outputPacket = true;
11350
11351 if (m_debugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
11352 outputPacket = false;
11353
11354 if (m_debugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
11355 outputPacket = false;
11356
11357 if (m_debugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
11358 outputPacket = false;
11359
11360 if (outputPacket)
11361 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11362 }
11363 11453
11364 if (!ProcessPacketMethod(packet)) 11454 if (!ProcessPacketMethod(packet))
11365 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 11455 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
@@ -11601,7 +11691,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11601 11691
11602// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 11692// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11603 11693
11694
11695 //Note, the bool returned from the below function is useless since it is always false.
11604 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 11696 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11697
11605 } 11698 }
11606 11699
11607 /// <summary> 11700 /// <summary>