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.cs798
1 files changed, 494 insertions, 304 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 1f7e66d..cd438d6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -157,6 +157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
157 public event RequestTaskInventory OnRequestTaskInventory; 157 public event RequestTaskInventory OnRequestTaskInventory;
158 public event UpdateInventoryItem OnUpdateInventoryItem; 158 public event UpdateInventoryItem OnUpdateInventoryItem;
159 public event CopyInventoryItem OnCopyInventoryItem; 159 public event CopyInventoryItem OnCopyInventoryItem;
160 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
160 public event MoveInventoryItem OnMoveInventoryItem; 161 public event MoveInventoryItem OnMoveInventoryItem;
161 public event RemoveInventoryItem OnRemoveInventoryItem; 162 public event RemoveInventoryItem OnRemoveInventoryItem;
162 public event RemoveInventoryFolder OnRemoveInventoryFolder; 163 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -254,7 +255,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
254 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 255 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
255 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 256 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
256 public event ClassifiedDelete OnClassifiedDelete; 257 public event ClassifiedDelete OnClassifiedDelete;
257 public event ClassifiedDelete OnClassifiedGodDelete; 258 public event ClassifiedGodDelete OnClassifiedGodDelete;
258 public event EventNotificationAddRequest OnEventNotificationAddRequest; 259 public event EventNotificationAddRequest OnEventNotificationAddRequest;
259 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 260 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
260 public event EventGodDelete OnEventGodDelete; 261 public event EventGodDelete OnEventGodDelete;
@@ -330,7 +331,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
330 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 331 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
331 /// ownerless phantom. 332 /// ownerless phantom.
332 /// 333 ///
333 /// All manipulation of this set has to occur under a lock 334 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
334 /// 335 ///
335 /// </value> 336 /// </value>
336 protected HashSet<uint> m_killRecord; 337 protected HashSet<uint> m_killRecord;
@@ -338,6 +339,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
338// protected HashSet<uint> m_attachmentsSent; 339// protected HashSet<uint> m_attachmentsSent;
339 340
340 private int m_moneyBalance; 341 private int m_moneyBalance;
342 private bool m_deliverPackets = true;
341 private int m_animationSequenceNumber = 1; 343 private int m_animationSequenceNumber = 1;
342 private bool m_SendLogoutPacketWhenClosing = true; 344 private bool m_SendLogoutPacketWhenClosing = true;
343 private AgentUpdateArgs lastarg; 345 private AgentUpdateArgs lastarg;
@@ -378,6 +380,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
378 get { return m_startpos; } 380 get { return m_startpos; }
379 set { m_startpos = value; } 381 set { m_startpos = value; }
380 } 382 }
383 public bool DeliverPackets
384 {
385 get { return m_deliverPackets; }
386 set {
387 m_deliverPackets = value;
388 m_udpClient.m_deliverPackets = value;
389 }
390 }
381 public UUID AgentId { get { return m_agentId; } } 391 public UUID AgentId { get { return m_agentId; } }
382 public UUID ActiveGroupId { get { return m_activeGroupID; } } 392 public UUID ActiveGroupId { get { return m_activeGroupID; } }
383 public string ActiveGroupName { get { return m_activeGroupName; } } 393 public string ActiveGroupName { get { return m_activeGroupName; } }
@@ -474,18 +484,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
474 484
475 #region Client Methods 485 #region Client Methods
476 486
487
477 /// <summary> 488 /// <summary>
478 /// Shut down the client view 489 /// Shut down the client view
479 /// </summary> 490 /// </summary>
480 public void Close() 491 public void Close()
481 { 492 {
493 Close(true);
494 }
495
496 /// <summary>
497 /// Shut down the client view
498 /// </summary>
499 public void Close(bool sendStop)
500 {
482 m_log.DebugFormat( 501 m_log.DebugFormat(
483 "[CLIENT]: Close has been called for {0} attached to scene {1}", 502 "[CLIENT]: Close has been called for {0} attached to scene {1}",
484 Name, m_scene.RegionInfo.RegionName); 503 Name, m_scene.RegionInfo.RegionName);
485 504
486 // Send the STOP packet 505 if (sendStop)
487 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 506 {
488 OutPacket(disable, ThrottleOutPacketType.Unknown); 507 // Send the STOP packet
508 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
509 OutPacket(disable, ThrottleOutPacketType.Unknown);
510 }
489 511
490 IsActive = false; 512 IsActive = false;
491 513
@@ -766,7 +788,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
766 reply.ChatData.OwnerID = fromAgentID; 788 reply.ChatData.OwnerID = fromAgentID;
767 reply.ChatData.SourceID = fromAgentID; 789 reply.ChatData.SourceID = fromAgentID;
768 790
769 OutPacket(reply, ThrottleOutPacketType.Task); 791 OutPacket(reply, ThrottleOutPacketType.Unknown);
770 } 792 }
771 793
772 /// <summary> 794 /// <summary>
@@ -1052,6 +1074,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1052 public virtual void SendLayerData(float[] map) 1074 public virtual void SendLayerData(float[] map)
1053 { 1075 {
1054 Util.FireAndForget(DoSendLayerData, map); 1076 Util.FireAndForget(DoSendLayerData, map);
1077
1078 // Send it sync, and async. It's not that much data
1079 // and it improves user experience just so much!
1080 DoSendLayerData(map);
1055 } 1081 }
1056 1082
1057 /// <summary> 1083 /// <summary>
@@ -1064,16 +1090,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1064 1090
1065 try 1091 try
1066 { 1092 {
1067 //for (int y = 0; y < 16; y++) 1093 for (int y = 0; y < 16; y++)
1068 //{ 1094 {
1069 // for (int x = 0; x < 16; x++) 1095 for (int x = 0; x < 16; x+=4)
1070 // { 1096 {
1071 // SendLayerData(x, y, map); 1097 SendLayerPacket(x, y, map);
1072 // } 1098 }
1073 //} 1099 }
1074
1075 // Send LayerData in a spiral pattern. Fun!
1076 SendLayerTopRight(map, 0, 0, 15, 15);
1077 } 1100 }
1078 catch (Exception e) 1101 catch (Exception e)
1079 { 1102 {
@@ -1081,51 +1104,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1081 } 1104 }
1082 } 1105 }
1083 1106
1084 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1085 {
1086 // Row
1087 for (int i = x1; i <= x2; i++)
1088 SendLayerData(i, y1, map);
1089
1090 // Column
1091 for (int j = y1 + 1; j <= y2; j++)
1092 SendLayerData(x2, j, map);
1093
1094 if (x2 - x1 > 0)
1095 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1096 }
1097
1098 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1099 {
1100 // Row in reverse
1101 for (int i = x2; i >= x1; i--)
1102 SendLayerData(i, y2, map);
1103
1104 // Column in reverse
1105 for (int j = y2 - 1; j >= y1; j--)
1106 SendLayerData(x1, j, map);
1107
1108 if (x2 - x1 > 0)
1109 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1110 }
1111
1112 /// <summary> 1107 /// <summary>
1113 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1108 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1114 /// </summary> 1109 /// </summary>
1115 /// <param name="map">heightmap</param> 1110 /// <param name="map">heightmap</param>
1116 /// <param name="px">X coordinate for patches 0..12</param> 1111 /// <param name="px">X coordinate for patches 0..12</param>
1117 /// <param name="py">Y coordinate for patches 0..15</param> 1112 /// <param name="py">Y coordinate for patches 0..15</param>
1118 // private void SendLayerPacket(float[] map, int y, int x) 1113 private void SendLayerPacket(int x, int y, float[] map)
1119 // { 1114 {
1120 // int[] patches = new int[4]; 1115 int[] patches = new int[4];
1121 // patches[0] = x + 0 + y * 16; 1116 patches[0] = x + 0 + y * 16;
1122 // patches[1] = x + 1 + y * 16; 1117 patches[1] = x + 1 + y * 16;
1123 // patches[2] = x + 2 + y * 16; 1118 patches[2] = x + 2 + y * 16;
1124 // patches[3] = x + 3 + y * 16; 1119 patches[3] = x + 3 + y * 16;
1125 1120
1126 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1121 float[] heightmap = (map.Length == 65536) ?
1127 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1122 map :
1128 // } 1123 LLHeightFieldMoronize(map);
1124
1125 try
1126 {
1127 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1128 OutPacket(layerpack, ThrottleOutPacketType.Land);
1129 }
1130 catch
1131 {
1132 for (int px = x ; px < x + 4 ; px++)
1133 SendLayerData(px, y, map);
1134 }
1135 }
1129 1136
1130 /// <summary> 1137 /// <summary>
1131 /// Sends a specified patch to a client 1138 /// Sends a specified patch to a client
@@ -1145,7 +1152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1145 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1152 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1146 layerpack.Header.Reliable = true; 1153 layerpack.Header.Reliable = true;
1147 1154
1148 OutPacket(layerpack, ThrottleOutPacketType.Land); 1155 OutPacket(layerpack, ThrottleOutPacketType.Task);
1149 } 1156 }
1150 catch (Exception e) 1157 catch (Exception e)
1151 { 1158 {
@@ -1506,38 +1513,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1506 OutPacket(pc, ThrottleOutPacketType.Unknown); 1513 OutPacket(pc, ThrottleOutPacketType.Unknown);
1507 } 1514 }
1508 1515
1509 public void SendKillObject(ulong regionHandle, uint localID) 1516 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1510 { 1517 {
1511// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1518// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1512 1519
1513 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1520 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1514 // TODO: don't create new blocks if recycling an old packet 1521 // TODO: don't create new blocks if recycling an old packet
1515 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; 1522 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1516 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); 1523 for (int i = 0 ; i < localIDs.Count ; i++ )
1517 kill.ObjectData[0].ID = localID; 1524 {
1525 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1526 kill.ObjectData[i].ID = localIDs[i];
1527 }
1518 kill.Header.Reliable = true; 1528 kill.Header.Reliable = true;
1519 kill.Header.Zerocoded = true; 1529 kill.Header.Zerocoded = true;
1520 1530
1521 if (m_scene.GetScenePresence(localID) == null) 1531 lock (m_killRecord)
1522 { 1532 {
1523 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 1533 if (localIDs.Count == 1)
1524 // condition where a kill can be processed before an out-of-date update for the same object.
1525 lock (m_killRecord)
1526 { 1534 {
1527 m_killRecord.Add(localID); 1535 if (m_scene.GetScenePresence(localIDs[0]) != null)
1528 1536 {
1529 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1537 OutPacket(kill, ThrottleOutPacketType.State);
1530 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1538 return;
1531 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1539 }
1532 // scene objects in a viewer until that viewer is relogged in. 1540 m_killRecord.Add(localIDs[0]);
1533 OutPacket(kill, ThrottleOutPacketType.Task); 1541 }
1542 else
1543 {
1544 lock (m_entityUpdates.SyncRoot)
1545 {
1546 foreach (uint localID in localIDs)
1547 m_killRecord.Add(localID);
1548 }
1534 } 1549 }
1535 } 1550 }
1536 else 1551
1537 { 1552 // The throttle queue used here must match that being used for
1538 // OutPacket(kill, ThrottleOutPacketType.State); 1553 // updates. Otherwise, there is a chance that a kill packet put
1539 OutPacket(kill, ThrottleOutPacketType.Task); 1554 // on a separate queue will be sent to the client before an
1540 } 1555 // existing update packet on another queue. Receiving updates
1556 // after kills results in unowned and undeletable
1557 // scene objects in a viewer until that viewer is relogged in.
1558 OutPacket(kill, ThrottleOutPacketType.Task);
1541 } 1559 }
1542 1560
1543 /// <summary> 1561 /// <summary>
@@ -2250,6 +2268,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2250 OutPacket(sound, ThrottleOutPacketType.Task); 2268 OutPacket(sound, ThrottleOutPacketType.Task);
2251 } 2269 }
2252 2270
2271 public void SendTransferAbort(TransferRequestPacket transferRequest)
2272 {
2273 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2274 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2275 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2276 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2277 OutPacket(abort, ThrottleOutPacketType.Task);
2278 }
2279
2253 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2280 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2254 { 2281 {
2255 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2282 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -3554,13 +3581,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3554 /// </summary> 3581 /// </summary>
3555 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3582 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3556 { 3583 {
3557 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3584 if (entity is SceneObjectPart)
3585 {
3586 SceneObjectPart e = (SceneObjectPart)entity;
3587 SceneObjectGroup g = e.ParentGroup;
3588 if (g.RootPart.Shape.State > 30) // HUD
3589 if (g.OwnerID != AgentId)
3590 return; // Don't send updates for other people's HUDs
3591 }
3592
3558 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3593 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3559 3594
3560 lock (m_entityUpdates.SyncRoot) 3595 lock (m_entityUpdates.SyncRoot)
3561 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3596 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3562 } 3597 }
3563 3598
3599 /// <summary>
3600 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3601 /// We will update the priority and put it in the correct queue, merging update flags
3602 /// with any other updates that may be queued for the same entity.
3603 /// The original update time is used for the merged update.
3604 /// </summary>
3605 private void ResendPrimUpdate(EntityUpdate update)
3606 {
3607 // If the update exists in priority queue, it will be updated.
3608 // If it does not exist then it will be added with the current (rather than its original) priority
3609 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3610
3611 lock (m_entityUpdates.SyncRoot)
3612 m_entityUpdates.Enqueue(priority, update);
3613 }
3614
3615 /// <summary>
3616 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3617 /// We will update the priority and put it in the correct queue, merging update flags
3618 /// with any other updates that may be queued for the same entity.
3619 /// The original update time is used for the merged update.
3620 /// </summary>
3621 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
3622 {
3623 // m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime);
3624
3625 // Remove the update packet from the list of packets waiting for acknowledgement
3626 // because we are requeuing the list of updates. They will be resent in new packets
3627 // with the most recent state and priority.
3628 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true);
3629 foreach (EntityUpdate update in updates)
3630 ResendPrimUpdate(update);
3631 }
3632
3564 private void ProcessEntityUpdates(int maxUpdates) 3633 private void ProcessEntityUpdates(int maxUpdates)
3565 { 3634 {
3566 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3635 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3568,6 +3637,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3568 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3637 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3569 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3638 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3570 3639
3640 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3641 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3642 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3643 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3644
3571 // Check to see if this is a flush 3645 // Check to see if this is a flush
3572 if (maxUpdates <= 0) 3646 if (maxUpdates <= 0)
3573 { 3647 {
@@ -3578,207 +3652,230 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3578 3652
3579 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3653 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3580 // condition where a kill can be processed before an out-of-date update for the same object. 3654 // condition where a kill can be processed before an out-of-date update for the same object.
3581 lock (m_killRecord) 3655 float avgTimeDilation = 1.0f;
3582 { 3656 IEntityUpdate iupdate;
3583 float avgTimeDilation = 1.0f; 3657 Int32 timeinqueue; // this is just debugging code & can be dropped later
3584 IEntityUpdate iupdate;
3585 Int32 timeinqueue; // this is just debugging code & can be dropped later
3586 3658
3587 while (updatesThisCall < maxUpdates) 3659 while (updatesThisCall < maxUpdates)
3588 { 3660 {
3589 lock (m_entityUpdates.SyncRoot) 3661 lock (m_entityUpdates.SyncRoot)
3590 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) 3662 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3591 break; 3663 break;
3592 3664
3593 EntityUpdate update = (EntityUpdate)iupdate; 3665 EntityUpdate update = (EntityUpdate)iupdate;
3594 3666
3595 avgTimeDilation += update.TimeDilation; 3667 avgTimeDilation += update.TimeDilation;
3596 avgTimeDilation *= 0.5f; 3668 avgTimeDilation *= 0.5f;
3597 3669
3598 if (update.Entity is SceneObjectPart) 3670 if (update.Entity is SceneObjectPart)
3671 {
3672 SceneObjectPart part = (SceneObjectPart)update.Entity;
3673
3674 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3675 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3676 // safety measure.
3677 //
3678 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3679 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3680 // updates and kills on different threads with different scheduling strategies, hence this protection.
3681 //
3682 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3683 // after the root prim has been deleted.
3684 lock (m_killRecord)
3599 { 3685 {
3600 SceneObjectPart part = (SceneObjectPart)update.Entity;
3601
3602 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3603 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3604 // safety measure.
3605 //
3606 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3607 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3608 // updates and kills on different threads with different scheduling strategies, hence this protection.
3609 //
3610 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3611 // after the root prim has been deleted.
3612 if (m_killRecord.Contains(part.LocalId)) 3686 if (m_killRecord.Contains(part.LocalId))
3613 {
3614 // m_log.WarnFormat(
3615 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
3616 // part.LocalId, Name);
3617 continue; 3687 continue;
3618 } 3688 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3619 3689 continue;
3620 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3690 }
3691
3692 if (part.ParentGroup.IsDeleted)
3693 continue;
3694
3695 if (part.ParentGroup.IsAttachment)
3696 { // Someone else's HUD, why are we getting these?
3697 if (part.ParentGroup.OwnerID != AgentId &&
3698 part.ParentGroup.RootPart.Shape.State >= 30)
3699 continue;
3700 ScenePresence sp;
3701 // Owner is not in the sim, don't update it to
3702 // anyone
3703 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3704 continue;
3705
3706 List<SceneObjectGroup> atts = sp.Attachments;
3707 bool found = false;
3708 foreach (SceneObjectGroup att in atts)
3621 { 3709 {
3622 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3710 if (att == part.ParentGroup)
3623 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3624 { 3711 {
3625 part.Shape.LightEntry = false; 3712 found = true;
3713 break;
3626 } 3714 }
3627 } 3715 }
3716
3717 // It's an attachment of a valid avatar, but
3718 // doesn't seem to be attached, skip
3719 if (!found)
3720 continue;
3628 } 3721 }
3629 3722 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3630 ++updatesThisCall;
3631
3632 #region UpdateFlags to packet type conversion
3633
3634 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3635
3636 bool canUseCompressed = true;
3637 bool canUseImproved = true;
3638
3639 // Compressed object updates only make sense for LL primitives
3640 if (!(update.Entity is SceneObjectPart))
3641 {
3642 canUseCompressed = false;
3643 }
3644
3645 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3646 {
3647 canUseCompressed = false;
3648 canUseImproved = false;
3649 }
3650 else
3651 { 3723 {
3652 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3724 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3653 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || 3725 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3654 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3655 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3656 { 3726 {
3657 canUseCompressed = false; 3727 part.Shape.LightEntry = false;
3658 }
3659
3660 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3661 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3662 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3663 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3664 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3665 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3666 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3667 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3668 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3669 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3670 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3671 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3672 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3673 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3674 {
3675 canUseImproved = false;
3676 } 3728 }
3677 } 3729 }
3678 3730 }
3679 #endregion UpdateFlags to packet type conversion 3731
3680 3732 ++updatesThisCall;
3681 #region Block Construction 3733
3682 3734 #region UpdateFlags to packet type conversion
3683 // TODO: Remove this once we can build compressed updates 3735
3736 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3737
3738 bool canUseCompressed = true;
3739 bool canUseImproved = true;
3740
3741 // Compressed object updates only make sense for LL primitives
3742 if (!(update.Entity is SceneObjectPart))
3743 {
3684 canUseCompressed = false; 3744 canUseCompressed = false;
3685 3745 }
3686 if (!canUseImproved && !canUseCompressed) 3746
3747 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3748 {
3749 canUseCompressed = false;
3750 canUseImproved = false;
3751 }
3752 else
3753 {
3754 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3755 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3756 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3757 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3687 { 3758 {
3688 if (update.Entity is ScenePresence) 3759 canUseCompressed = false;
3689 {
3690 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3691 }
3692 else
3693 {
3694 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3695 }
3696 } 3760 }
3697 else if (!canUseImproved) 3761
3762 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3763 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3764 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3765 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3766 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3767 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3768 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3769 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3770 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3771 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3772 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3773 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3774 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3775 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3776 {
3777 canUseImproved = false;
3778 }
3779 }
3780
3781 #endregion UpdateFlags to packet type conversion
3782
3783 #region Block Construction
3784
3785 // TODO: Remove this once we can build compressed updates
3786 canUseCompressed = false;
3787
3788 if (!canUseImproved && !canUseCompressed)
3789 {
3790 if (update.Entity is ScenePresence)
3698 { 3791 {
3699 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3792 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3700 } 3793 }
3701 else 3794 else
3702 { 3795 {
3703 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3796 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3704 // Self updates go into a special list
3705 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3706 else
3707 // Everything else goes here
3708 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3709 } 3797 }
3710
3711 #endregion Block Construction
3712 } 3798 }
3713 3799 else if (!canUseImproved)
3800 {
3801 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3802 }
3803 else
3804 {
3805 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3806 // Self updates go into a special list
3807 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3808 else
3809 // Everything else goes here
3810 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3811 }
3812
3813 #endregion Block Construction
3814 }
3815
3816 #region Packet Sending
3714 3817
3715 #region Packet Sending 3818 const float TIME_DILATION = 1.0f;
3716 3819 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3717 //const float TIME_DILATION = 1.0f; 3820
3821 if (terseAgentUpdateBlocks.IsValueCreated)
3822 {
3823 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3824
3825 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3826 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3827 packet.RegionData.TimeDilation = timeDilation;
3828 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3718 3829
3830 for (int i = 0; i < blocks.Count; i++)
3831 packet.ObjectData[i] = blocks[i];
3832
3833 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3834 }
3719 3835
3720 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3836 if (objectUpdateBlocks.IsValueCreated)
3837 {
3838 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3721 3839
3722 if (terseAgentUpdateBlocks.IsValueCreated) 3840 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3723 { 3841 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3724 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3842 packet.RegionData.TimeDilation = timeDilation;
3843 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3725 3844
3726 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3845 for (int i = 0; i < blocks.Count; i++)
3727 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3846 packet.ObjectData[i] = blocks[i];
3728 packet.RegionData.TimeDilation = timeDilation; 3847
3729 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3848 OutPacket(packet, ThrottleOutPacketType.Task, true);
3849 }
3730 3850
3731 for (int i = 0; i < blocks.Count; i++) 3851 if (compressedUpdateBlocks.IsValueCreated)
3732 packet.ObjectData[i] = blocks[i]; 3852 {
3853 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3854
3855 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3856 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3857 packet.RegionData.TimeDilation = timeDilation;
3858 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3733 3859
3734 3860 for (int i = 0; i < blocks.Count; i++)
3735 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 3861 packet.ObjectData[i] = blocks[i];
3736 }
3737 3862
3738 if (objectUpdateBlocks.IsValueCreated) 3863 OutPacket(packet, ThrottleOutPacketType.Task, true);
3739 { 3864 }
3740 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3865
3741 3866 if (terseUpdateBlocks.IsValueCreated)
3742 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3867 {
3743 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3868 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3744 packet.RegionData.TimeDilation = timeDilation; 3869
3745 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3870 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3746 3871 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3747 for (int i = 0; i < blocks.Count; i++) 3872 packet.RegionData.TimeDilation = timeDilation;
3748 packet.ObjectData[i] = blocks[i]; 3873 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3749 3874
3750 OutPacket(packet, ThrottleOutPacketType.Task, true); 3875 for (int i = 0; i < blocks.Count; i++)
3751 } 3876 packet.ObjectData[i] = blocks[i];
3752 3877
3753 if (compressedUpdateBlocks.IsValueCreated) 3878 OutPacket(packet, ThrottleOutPacketType.Task, true);
3754 {
3755 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3756
3757 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3758 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3759 packet.RegionData.TimeDilation = timeDilation;
3760 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3761
3762 for (int i = 0; i < blocks.Count; i++)
3763 packet.ObjectData[i] = blocks[i];
3764
3765 OutPacket(packet, ThrottleOutPacketType.Task, true);
3766 }
3767
3768 if (terseUpdateBlocks.IsValueCreated)
3769 {
3770 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3771
3772 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3773 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3774 packet.RegionData.TimeDilation = timeDilation;
3775 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3776
3777 for (int i = 0; i < blocks.Count; i++)
3778 packet.ObjectData[i] = blocks[i];
3779
3780 OutPacket(packet, ThrottleOutPacketType.Task, true);
3781 }
3782 } 3879 }
3783 3880
3784 #endregion Packet Sending 3881 #endregion Packet Sending
@@ -3969,7 +4066,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3969 { 4066 {
3970 SendFamilyProps = SendFamilyProps || update.SendFamilyProps; 4067 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
3971 SendObjectProps = SendObjectProps || update.SendObjectProps; 4068 SendObjectProps = SendObjectProps || update.SendObjectProps;
3972 Flags |= update.Flags; 4069 // other properties may need to be updated by base class
4070 base.Update(update);
3973 } 4071 }
3974 } 4072 }
3975 4073
@@ -3980,6 +4078,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3980 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); 4078 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
3981 } 4079 }
3982 4080
4081 private void ResendPropertyUpdate(ObjectPropertyUpdate update)
4082 {
4083 uint priority = 0;
4084 lock (m_entityProps.SyncRoot)
4085 m_entityProps.Enqueue(priority, update);
4086 }
4087
4088 private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket)
4089 {
4090 // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime);
4091
4092 // Remove the update packet from the list of packets waiting for acknowledgement
4093 // because we are requeuing the list of updates. They will be resent in new packets
4094 // with the most recent state.
4095 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true);
4096 foreach (ObjectPropertyUpdate update in updates)
4097 ResendPropertyUpdate(update);
4098 }
4099
3983 public void SendObjectPropertiesReply(ISceneEntity entity) 4100 public void SendObjectPropertiesReply(ISceneEntity entity)
3984 { 4101 {
3985 uint priority = 0; // time based ordering only 4102 uint priority = 0; // time based ordering only
@@ -3995,6 +4112,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3995 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = 4112 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
3996 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); 4113 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
3997 4114
4115 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
4116 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4117
4118 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
4119 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4120
3998 IEntityUpdate iupdate; 4121 IEntityUpdate iupdate;
3999 Int32 timeinqueue; // this is just debugging code & can be dropped later 4122 Int32 timeinqueue; // this is just debugging code & can be dropped later
4000 4123
@@ -4013,6 +4136,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4013 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4136 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4014 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); 4137 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
4015 objectFamilyBlocks.Value.Add(objPropDB); 4138 objectFamilyBlocks.Value.Add(objPropDB);
4139 familyUpdates.Value.Add(update);
4016 } 4140 }
4017 } 4141 }
4018 4142
@@ -4023,6 +4147,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4023 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4147 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4024 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); 4148 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
4025 objectPropertiesBlocks.Value.Add(objPropDB); 4149 objectPropertiesBlocks.Value.Add(objPropDB);
4150 propertyUpdates.Value.Add(update);
4026 } 4151 }
4027 } 4152 }
4028 4153
@@ -4030,12 +4155,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4030 } 4155 }
4031 4156
4032 4157
4033 Int32 ppcnt = 0; 4158 // Int32 ppcnt = 0;
4034 Int32 pbcnt = 0; 4159 // Int32 pbcnt = 0;
4035 4160
4036 if (objectPropertiesBlocks.IsValueCreated) 4161 if (objectPropertiesBlocks.IsValueCreated)
4037 { 4162 {
4038 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; 4163 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
4164 List<ObjectPropertyUpdate> updates = propertyUpdates.Value;
4039 4165
4040 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4166 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4041 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; 4167 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
@@ -4043,28 +4169,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4043 packet.ObjectData[i] = blocks[i]; 4169 packet.ObjectData[i] = blocks[i];
4044 4170
4045 packet.Header.Zerocoded = true; 4171 packet.Header.Zerocoded = true;
4046 OutPacket(packet, ThrottleOutPacketType.Task, true);
4047 4172
4048 pbcnt += blocks.Count; 4173 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4049 ppcnt++; 4174 // of the object rather than the properties when the packet was created
4175 OutPacket(packet, ThrottleOutPacketType.Task, true,
4176 delegate(OutgoingPacket oPacket)
4177 {
4178 ResendPropertyUpdates(updates, oPacket);
4179 });
4180
4181 // pbcnt += blocks.Count;
4182 // ppcnt++;
4050 } 4183 }
4051 4184
4052 Int32 fpcnt = 0; 4185 // Int32 fpcnt = 0;
4053 Int32 fbcnt = 0; 4186 // Int32 fbcnt = 0;
4054 4187
4055 if (objectFamilyBlocks.IsValueCreated) 4188 if (objectFamilyBlocks.IsValueCreated)
4056 { 4189 {
4057 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; 4190 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
4058 4191
4059 // ObjectPropertiesFamilyPacket objPropFamilyPack =
4060 // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
4061 //
4062 // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count];
4063 // for (int i = 0; i < blocks.Count; i++)
4064 // objPropFamilyPack.ObjectData[i] = blocks[i];
4065 //
4066 // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true);
4067
4068 // one packet per object block... uggh... 4192 // one packet per object block... uggh...
4069 for (int i = 0; i < blocks.Count; i++) 4193 for (int i = 0; i < blocks.Count; i++)
4070 { 4194 {
@@ -4073,10 +4197,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4073 4197
4074 packet.ObjectData = blocks[i]; 4198 packet.ObjectData = blocks[i];
4075 packet.Header.Zerocoded = true; 4199 packet.Header.Zerocoded = true;
4076 OutPacket(packet, ThrottleOutPacketType.Task);
4077 4200
4078 fpcnt++; 4201 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4079 fbcnt++; 4202 // of the object rather than the properties when the packet was created
4203 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4204 updates.Add(familyUpdates.Value[i]);
4205 OutPacket(packet, ThrottleOutPacketType.Task, true,
4206 delegate(OutgoingPacket oPacket)
4207 {
4208 ResendPropertyUpdates(updates, oPacket);
4209 });
4210
4211 // fpcnt++;
4212 // fbcnt++;
4080 } 4213 }
4081 4214
4082 } 4215 }
@@ -4113,7 +4246,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4113 4246
4114 return block; 4247 return block;
4115 } 4248 }
4116 4249
4117 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) 4250 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
4118 { 4251 {
4119 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4252 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
@@ -4550,14 +4683,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4550 4683
4551 if (notifyCount > 0) 4684 if (notifyCount > 0)
4552 { 4685 {
4553 if (notifyCount > 32) 4686// if (notifyCount > 32)
4554 { 4687// {
4555 m_log.InfoFormat( 4688// m_log.InfoFormat(
4556 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4689// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4557 + " - a developer might want to investigate whether this is a hard limit", 32); 4690// + " - a developer might want to investigate whether this is a hard limit", 32);
4558 4691//
4559 notifyCount = 32; 4692// notifyCount = 32;
4560 } 4693// }
4561 4694
4562 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4695 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4563 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4696 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -5065,6 +5198,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5065 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5198 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5066 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5199 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5067 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5200 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5201 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5068 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5202 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5069 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5203 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5070 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5204 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5164,6 +5298,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5164 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5298 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5165 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5299 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5166 (x.ControlFlags != lastarg.ControlFlags) || 5300 (x.ControlFlags != lastarg.ControlFlags) ||
5301 (x.ControlFlags != 0) ||
5167 (x.Far != lastarg.Far) || 5302 (x.Far != lastarg.Far) ||
5168 (x.Flags != lastarg.Flags) || 5303 (x.Flags != lastarg.Flags) ||
5169 (x.State != lastarg.State) || 5304 (x.State != lastarg.State) ||
@@ -5537,7 +5672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5537 args.Channel = ch; 5672 args.Channel = ch;
5538 args.From = String.Empty; 5673 args.From = String.Empty;
5539 args.Message = Utils.BytesToString(msg); 5674 args.Message = Utils.BytesToString(msg);
5540 args.Type = ChatTypeEnum.Shout; 5675 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5541 args.Position = new Vector3(); 5676 args.Position = new Vector3();
5542 args.Scene = Scene; 5677 args.Scene = Scene;
5543 args.Sender = this; 5678 args.Sender = this;
@@ -9525,7 +9660,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9525 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 9660 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9526 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 9661 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9527 UpdateMuteListEntry.MuteData.MuteType, 9662 UpdateMuteListEntry.MuteData.MuteType,
9528 UpdateMuteListEntry.AgentData.AgentID); 9663 UpdateMuteListEntry.MuteData.MuteFlags);
9529 return true; 9664 return true;
9530 } 9665 }
9531 return false; 9666 return false;
@@ -9540,8 +9675,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9540 { 9675 {
9541 handlerRemoveMuteListEntry(this, 9676 handlerRemoveMuteListEntry(this,
9542 RemoveMuteListEntry.MuteData.MuteID, 9677 RemoveMuteListEntry.MuteData.MuteID,
9543 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 9678 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9544 RemoveMuteListEntry.AgentData.AgentID);
9545 return true; 9679 return true;
9546 } 9680 }
9547 return false; 9681 return false;
@@ -9589,6 +9723,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9589 { 9723 {
9590 return true; 9724 return true;
9591 } 9725 }
9726
9727 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9728 {
9729 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9730
9731 #region Packet Session and User Check
9732 if (m_checkPackets)
9733 {
9734 if (packet.AgentData.SessionID != SessionId ||
9735 packet.AgentData.AgentID != AgentId)
9736 return true;
9737 }
9738 #endregion
9739 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9740 List<InventoryItemBase> items = new List<InventoryItemBase>();
9741 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9742 {
9743 InventoryItemBase b = new InventoryItemBase();
9744 b.ID = n.OldItemID;
9745 b.Folder = n.OldFolderID;
9746 items.Add(b);
9747 }
9748
9749 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9750 if (handlerMoveItemsAndLeaveCopy != null)
9751 {
9752 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9753 }
9754
9755 return true;
9756 }
9592 9757
9593 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9758 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9594 { 9759 {
@@ -10015,6 +10180,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10015 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10180 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10016 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10181 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10017 10182
10183 Scene scene = (Scene)m_scene;
10184 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10185 {
10186 ScenePresence p;
10187 if (scene.TryGetScenePresence(sender.AgentId, out p))
10188 {
10189 if (p.GodLevel >= 200)
10190 {
10191 groupProfileReply.GroupData.OpenEnrollment = true;
10192 groupProfileReply.GroupData.MembershipFee = 0;
10193 }
10194 }
10195 }
10196
10018 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10197 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10019 } 10198 }
10020 return true; 10199 return true;
@@ -10587,11 +10766,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10587 10766
10588 StartLure handlerStartLure = OnStartLure; 10767 StartLure handlerStartLure = OnStartLure;
10589 if (handlerStartLure != null) 10768 if (handlerStartLure != null)
10590 handlerStartLure(startLureRequest.Info.LureType, 10769 {
10591 Utils.BytesToString( 10770 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10592 startLureRequest.Info.Message), 10771 {
10593 startLureRequest.TargetData[0].TargetID, 10772 handlerStartLure(startLureRequest.Info.LureType,
10594 this); 10773 Utils.BytesToString(
10774 startLureRequest.Info.Message),
10775 startLureRequest.TargetData[i].TargetID,
10776 this);
10777 }
10778 }
10595 return true; 10779 return true;
10596 } 10780 }
10597 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 10781 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -10705,10 +10889,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10705 } 10889 }
10706 #endregion 10890 #endregion
10707 10891
10708 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 10892 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
10709 if (handlerClassifiedGodDelete != null) 10893 if (handlerClassifiedGodDelete != null)
10710 handlerClassifiedGodDelete( 10894 handlerClassifiedGodDelete(
10711 classifiedGodDelete.Data.ClassifiedID, 10895 classifiedGodDelete.Data.ClassifiedID,
10896 classifiedGodDelete.Data.QueryID,
10712 this); 10897 this);
10713 return true; 10898 return true;
10714 } 10899 }
@@ -11086,7 +11271,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11086 { 11271 {
11087 // It's a ghost! tell the client to delete it from view. 11272 // It's a ghost! tell the client to delete it from view.
11088 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 11273 simClient.SendKillObject(Scene.RegionInfo.RegionHandle,
11089 localId); 11274 new List<uint>() { localId });
11090 } 11275 }
11091 else 11276 else
11092 { 11277 {
@@ -11363,6 +11548,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11363 /// handles splitting manually</param> 11548 /// handles splitting manually</param>
11364 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) 11549 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
11365 { 11550 {
11551 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
11552 }
11553
11554 /// <summary>
11555 /// This is the starting point for sending a simulator packet out to the client
11556 /// </summary>
11557 /// <param name="packet">Packet to send</param>
11558 /// <param name="throttlePacketType">Throttling category for the packet</param>
11559 /// <param name="doAutomaticSplitting">True to automatically split oversized
11560 /// packets (the default), or false to disable splitting if the calling code
11561 /// handles splitting manually</param>
11562 /// <param name="method">The method to be called in the event this packet is reliable
11563 /// and unacknowledged. The server will provide normal resend capability if you do not
11564 /// provide your own method.</param>
11565 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
11566 {
11366 if (m_debugPacketLevel > 0) 11567 if (m_debugPacketLevel > 0)
11367 { 11568 {
11368 bool logPacket = true; 11569 bool logPacket = true;
@@ -11388,7 +11589,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11388 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); 11589 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type);
11389 } 11590 }
11390 11591
11391 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); 11592 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11392 } 11593 }
11393 11594
11394 public bool AddMoney(int debit) 11595 public bool AddMoney(int debit)
@@ -11459,22 +11660,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11459 /// <param name="Pack">OpenMetaverse.packet</param> 11660 /// <param name="Pack">OpenMetaverse.packet</param>
11460 public void ProcessInPacket(Packet packet) 11661 public void ProcessInPacket(Packet packet)
11461 { 11662 {
11462 if (m_debugPacketLevel > 0) 11663 if (m_debugPacketLevel >= 255)
11463 { 11664 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11464 bool outputPacket = true;
11465
11466 if (m_debugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
11467 outputPacket = false;
11468
11469 if (m_debugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
11470 outputPacket = false;
11471
11472 if (m_debugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
11473 outputPacket = false;
11474
11475 if (outputPacket)
11476 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11477 }
11478 11665
11479 if (!ProcessPacketMethod(packet)) 11666 if (!ProcessPacketMethod(packet))
11480 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 11667 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
@@ -11716,7 +11903,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11716 11903
11717// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 11904// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11718 11905
11906
11907 //Note, the bool returned from the below function is useless since it is always false.
11719 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 11908 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11909
11720 } 11910 }
11721 11911
11722 /// <summary> 11912 /// <summary>