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.cs626
1 files changed, 299 insertions, 327 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 1f3582c..11dca8d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -50,43 +50,17 @@ using Nini.Config;
50 50
51namespace OpenSim.Region.ClientStack.LindenUDP 51namespace OpenSim.Region.ClientStack.LindenUDP
52{ 52{
53 #region Enums 53 public class EntityUpdate
54
55 /// <summary>
56 /// Specifies the fields that have been changed when sending a prim or
57 /// avatar update
58 /// </summary>
59 [Flags]
60 public enum PrimUpdateFlags : uint
61 { 54 {
62 None = 0, 55 public ISceneEntity Entity;
63 AttachmentPoint = 1 << 0, 56 public PrimUpdateFlags Flags;
64 Material = 1 << 1,
65 ClickAction = 1 << 2,
66 Scale = 1 << 3,
67 ParentID = 1 << 4,
68 PrimFlags = 1 << 5,
69 PrimData = 1 << 6,
70 MediaURL = 1 << 7,
71 ScratchPad = 1 << 8,
72 Textures = 1 << 9,
73 TextureAnim = 1 << 10,
74 NameValue = 1 << 11,
75 Position = 1 << 12,
76 Rotation = 1 << 13,
77 Velocity = 1 << 14,
78 Acceleration = 1 << 15,
79 AngularVelocity = 1 << 16,
80 CollisionPlane = 1 << 17,
81 Text = 1 << 18,
82 Particles = 1 << 19,
83 ExtraData = 1 << 20,
84 Sound = 1 << 21,
85 Joint = 1 << 22,
86 FullUpdate = UInt32.MaxValue
87 }
88 57
89 #endregion Enums 58 public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags)
59 {
60 Entity = entity;
61 Flags = flags;
62 }
63 }
90 64
91 public delegate bool PacketMethod(IClientAPI simClient, Packet packet); 65 public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
92 66
@@ -350,9 +324,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
350 private readonly IGroupsModule m_GroupsModule; 324 private readonly IGroupsModule m_GroupsModule;
351 325
352 private int m_cachedTextureSerial; 326 private int m_cachedTextureSerial;
353 protected PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates; 327 private PriorityQueue<double, EntityUpdate> m_entityUpdates;
354 private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates;
355 private PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates;
356 328
357 /// <value> 329 /// <value>
358 /// List used in construction of data blocks for an object update packet. This is to stop us having to 330 /// List used in construction of data blocks for an object update packet. This is to stop us having to
@@ -463,9 +435,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
463 435
464 m_scene = scene; 436 m_scene = scene;
465 437
466 m_avatarTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); 438 m_entityUpdates = new PriorityQueue<double, EntityUpdate>(m_scene.Entities.Count);
467 m_primTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
468 m_primFullUpdates = new PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>(m_scene.Entities.Count);
469 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 439 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
470 m_killRecord = new HashSet<uint>(); 440 m_killRecord = new HashSet<uint>();
471 441
@@ -1519,7 +1489,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1519 kill.Header.Reliable = true; 1489 kill.Header.Reliable = true;
1520 kill.Header.Zerocoded = true; 1490 kill.Header.Zerocoded = true;
1521 1491
1522 lock (m_primFullUpdates.SyncRoot) 1492 lock (m_entityUpdates.SyncRoot)
1523 { 1493 {
1524 m_killRecord.Add(localID); 1494 m_killRecord.Add(localID);
1525 OutPacket(kill, ThrottleOutPacketType.State); 1495 OutPacket(kill, ThrottleOutPacketType.State);
@@ -3419,71 +3389,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3419 /// <summary> 3389 /// <summary>
3420 /// Send an ObjectUpdate packet with information about an avatar 3390 /// Send an ObjectUpdate packet with information about an avatar
3421 /// </summary> 3391 /// </summary>
3422 public void SendAvatarData(SendAvatarData data) 3392 public void SendAvatarDataImmediate(ISceneEntity avatar)
3423 { 3393 {
3394 ScenePresence presence = avatar as ScenePresence;
3395 if (presence == null)
3396 return;
3397
3424 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3398 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3425 objupdate.Header.Zerocoded = true; 3399 objupdate.Header.Zerocoded = true;
3426 3400
3427 objupdate.RegionData.RegionHandle = data.RegionHandle; 3401 objupdate.RegionData.RegionHandle = presence.RegionHandle;
3428 objupdate.RegionData.TimeDilation = ushort.MaxValue; 3402 objupdate.RegionData.TimeDilation = ushort.MaxValue;
3429 3403
3430 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; 3404 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3431 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data); 3405 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3432 3406
3433 OutPacket(objupdate, ThrottleOutPacketType.Task); 3407 OutPacket(objupdate, ThrottleOutPacketType.Task);
3434 } 3408 }
3435 3409
3436 /// <summary>
3437 /// Send a terse positional/rotation/velocity update about an avatar
3438 /// to the client. This avatar can be that of the client itself.
3439 /// </summary>
3440 public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data)
3441 {
3442 if (data.Priority == double.NaN)
3443 {
3444 m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update");
3445 return;
3446 }
3447
3448 Quaternion rotation = data.Rotation;
3449 if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f)
3450 rotation = Quaternion.Identity;
3451
3452 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateImprovedTerseBlock(data);
3453
3454 lock (m_avatarTerseUpdates.SyncRoot)
3455 m_avatarTerseUpdates.Enqueue(data.Priority, terseBlock, data.LocalID);
3456
3457 // If we received an update about our own avatar, process the avatar update priority queue immediately
3458 if (data.AgentID == m_agentId)
3459 ProcessAvatarTerseUpdates();
3460 }
3461
3462 protected void ProcessAvatarTerseUpdates()
3463 {
3464 ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3465 terse.Header.Reliable = false;
3466 terse.Header.Zerocoded = true;
3467
3468 //terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock();
3469 terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle;
3470 terse.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue);
3471
3472 lock (m_avatarTerseUpdates.SyncRoot)
3473 {
3474 int count = Math.Min(m_avatarTerseUpdates.Count, m_udpServer.AvatarTerseUpdatesPerPacket);
3475 if (count == 0)
3476 return;
3477
3478 terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count];
3479 for (int i = 0; i < count; i++)
3480 terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue();
3481 }
3482
3483 // HACK: Using the task category until the tiered reprioritization code is in
3484 OutPacket(terse, ThrottleOutPacketType.Task);
3485 }
3486
3487 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) 3410 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations)
3488 { 3411 {
3489 if (!IsActive) return; // We don't need to update inactive clients. 3412 if (!IsActive) return; // We don't need to update inactive clients.
@@ -3528,172 +3451,187 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3528 3451
3529 #region Primitive Packet/Data Sending Methods 3452 #region Primitive Packet/Data Sending Methods
3530 3453
3531 public void SendPrimitiveToClient(SendPrimitiveData data) 3454 /// <summary>
3455 /// Generate one of the object update packets based on PrimUpdateFlags
3456 /// and broadcast the packet to clients
3457 /// </summary>
3458 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3532 { 3459 {
3533// string text = data.text; 3460 double priority;
3534// if (text.IndexOf("\n") >= 0)
3535// text = text.Remove(text.IndexOf("\n"));
3536// m_log.DebugFormat(
3537// "[CLIENT]: Placing request to send full info about prim {0} text {1} to client {2}",
3538// data.localID, text, Name);
3539
3540 if (data.priority == double.NaN)
3541 {
3542 m_log.Error("[LLClientView] SendPrimitiveToClient received a NaN priority, dropping update");
3543 return;
3544 }
3545
3546 Quaternion rotation = data.rotation;
3547 if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f)
3548 rotation = Quaternion.Identity;
3549
3550 if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD
3551 return;
3552 if (data.primShape.State != 0 && data.parentID == 0 && data.primShape.PCode == 9)
3553 return;
3554 3461
3555 ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data); 3462 if (entity is SceneObjectPart)
3463 priority = ((SceneObjectPart)entity).ParentGroup.GetUpdatePriority(this);
3464 else if (entity is ScenePresence)
3465 priority = ((ScenePresence)entity).GetUpdatePriority(this);
3466 else
3467 priority = 0.0d;
3556 3468
3557 lock (m_primFullUpdates.SyncRoot) 3469 lock (m_entityUpdates.SyncRoot)
3558 m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); 3470 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags), entity.LocalId);
3559 } 3471 }
3560 3472
3561 void ProcessPrimFullUpdates() 3473 private void ProcessEntityUpdates(int maxUpdates)
3562 { 3474 {
3563 ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3475 Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3564 outPacket.Header.Zerocoded = true; 3476 Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3477 Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3565 3478
3566 outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; 3479 if (maxUpdates <= 0) maxUpdates = Int32.MaxValue;
3567 outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); 3480 int updatesThisCall = 0;
3568 3481
3569 lock (m_primFullUpdates.SyncRoot) 3482 lock (m_entityUpdates.SyncRoot)
3570 { 3483 {
3571 int count = Math.Min(m_primFullUpdates.Count, m_udpServer.PrimFullUpdatesPerPacket); 3484 EntityUpdate update;
3572 if (count == 0) 3485 while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update))
3573 return;
3574
3575 m_fullUpdateDataBlocksBuilder.Clear();
3576
3577 for (int i = 0; i < count; i++)
3578 { 3486 {
3579 ObjectUpdatePacket.ObjectDataBlock block = m_primFullUpdates.Dequeue(); 3487 ++updatesThisCall;
3488
3489 #region UpdateFlags to packet type conversion
3580 3490
3581 if (!m_killRecord.Contains(block.ID)) 3491 PrimUpdateFlags updateFlags = update.Flags;
3492
3493 bool canUseCompressed = true;
3494 bool canUseImproved = true;
3495
3496 // Compressed object updates only make sense for LL primitives
3497 if (!(update.Entity is SceneObjectPart))
3498 canUseCompressed = false;
3499
3500 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3582 { 3501 {
3583 m_fullUpdateDataBlocksBuilder.Add(block); 3502 canUseCompressed = false;
3584 3503 canUseImproved = false;
3585// string text = Util.FieldToString(outPacket.ObjectData[i].Text);
3586// if (text.IndexOf("\n") >= 0)
3587// text = text.Remove(text.IndexOf("\n"));
3588// m_log.DebugFormat(
3589// "[CLIENT]: Sending full info about prim {0} text {1} to client {2}",
3590// outPacket.ObjectData[i].ID, text, Name);
3591 } 3504 }
3592// else 3505 else
3593// { 3506 {
3594// m_log.WarnFormat( 3507 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3595// "[CLIENT]: Preventing full update for {0} after kill to {1}", block.ID, Name); 3508 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3596// } 3509 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3510 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3511 {
3512 canUseCompressed = false;
3513 }
3514
3515 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3516 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3517 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3518 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3519 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3520 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3521 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3522 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3523 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3524 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3525 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3526 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3527 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3528 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3529 {
3530 canUseImproved = false;
3531 }
3532 }
3533
3534 #endregion UpdateFlags to packet type conversion
3535
3536 #region Block Construction
3537
3538 // TODO: Remove this once we can build compressed updates
3539 canUseCompressed = false;
3540
3541 if (!canUseImproved && !canUseCompressed)
3542 {
3543 if (update.Entity is ScenePresence)
3544 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3545 else
3546 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3547 }
3548 else if (!canUseImproved)
3549 {
3550 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3551 }
3552 else
3553 {
3554 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3555 }
3556
3557 #endregion Block Construction
3597 } 3558 }
3559 }
3598 3560
3599 outPacket.ObjectData = m_fullUpdateDataBlocksBuilder.ToArray(); 3561 #region Packet Sending
3600
3601 OutPacket(outPacket, ThrottleOutPacketType.State);
3602 }
3603 }
3604 3562
3605 public void SendPrimTerseUpdate(SendPrimitiveTerseData data) 3563 const float TIME_DILATION = 1.0f;
3606 { 3564 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
3607 if (data.Priority == double.NaN) 3565
3566 if (objectUpdateBlocks.IsValueCreated)
3608 { 3567 {
3609 m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update"); 3568 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3610 return;
3611 }
3612 3569
3613 Quaternion rotation = data.Rotation; 3570 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3614 if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) 3571 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3615 rotation = Quaternion.Identity; 3572 packet.RegionData.TimeDilation = timeDilation;
3573 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3616 3574
3617 if (data.AttachPoint > 30 && data.OwnerID != AgentId) // Someone else's HUD 3575 for (int i = 0; i < blocks.Count; i++)
3618 return; 3576 packet.ObjectData[i] = blocks[i];
3577
3578 OutPacket(packet, ThrottleOutPacketType.Task, true);
3579 }
3619 3580
3620 ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = CreateImprovedTerseBlock(data); 3581 if (compressedUpdateBlocks.IsValueCreated)
3582 {
3583 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3621 3584
3622 lock (m_primTerseUpdates.SyncRoot) 3585 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3623 m_primTerseUpdates.Enqueue(data.Priority, objectData, data.LocalID); 3586 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3624 } 3587 packet.RegionData.TimeDilation = timeDilation;
3588 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3625 3589
3626 void ProcessPrimTerseUpdates() 3590 for (int i = 0; i < blocks.Count; i++)
3627 { 3591 packet.ObjectData[i] = blocks[i];
3628 ImprovedTerseObjectUpdatePacket outPacket = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3629 outPacket.Header.Reliable = false;
3630 outPacket.Header.Zerocoded = true;
3631 3592
3632 outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; 3593 OutPacket(packet, ThrottleOutPacketType.Task, true);
3633 outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); 3594 }
3634 3595
3635 lock (m_primTerseUpdates.SyncRoot) 3596 if (terseUpdateBlocks.IsValueCreated)
3636 { 3597 {
3637 int count = Math.Min(m_primTerseUpdates.Count, m_udpServer.PrimTerseUpdatesPerPacket); 3598 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3638 if (count == 0) 3599
3639 return; 3600 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3601 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3602 packet.RegionData.TimeDilation = timeDilation;
3603 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3640 3604
3641 outPacket.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; 3605 for (int i = 0; i < blocks.Count; i++)
3642 for (int i = 0; i < count; i++) 3606 packet.ObjectData[i] = blocks[i];
3643 outPacket.ObjectData[i] = m_primTerseUpdates.Dequeue(); 3607
3608 OutPacket(packet, ThrottleOutPacketType.Task, true);
3644 } 3609 }
3645 3610
3646 OutPacket(outPacket, ThrottleOutPacketType.State); 3611 #endregion Packet Sending
3647 } 3612 }
3648 3613
3649 public void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) 3614 public void ReprioritizeUpdates(UpdatePriorityHandler handler)
3650 { 3615 {
3651 PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler terse_update_priority_handler = 3616 //m_log.Debug("[CLIENT]: Reprioritizing prim updates for " + m_firstName + " " + m_lastName);
3652 delegate(ref double priority, uint local_id) 3617
3653 { 3618 PriorityQueue<double, EntityUpdate>.UpdatePriorityHandler update_priority_handler =
3654 priority = handler(new UpdatePriorityData(priority, local_id));
3655 return priority != double.NaN;
3656 };
3657 PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler update_priority_handler =
3658 delegate(ref double priority, uint local_id) 3619 delegate(ref double priority, uint local_id)
3659 { 3620 {
3660 priority = handler(new UpdatePriorityData(priority, local_id)); 3621 priority = handler(new UpdatePriorityData(priority, local_id));
3661 return priority != double.NaN; 3622 return priority != double.NaN;
3662 }; 3623 };
3663 3624
3664 if ((type & StateUpdateTypes.AvatarTerse) != 0) 3625 lock (m_entityUpdates.SyncRoot)
3665 { 3626 m_entityUpdates.Reprioritize(update_priority_handler);
3666 lock (m_avatarTerseUpdates.SyncRoot)
3667 m_avatarTerseUpdates.Reprioritize(terse_update_priority_handler);
3668 }
3669
3670 if ((type & StateUpdateTypes.PrimitiveFull) != 0)
3671 {
3672 lock (m_primFullUpdates.SyncRoot)
3673 m_primFullUpdates.Reprioritize(update_priority_handler);
3674 }
3675
3676 if ((type & StateUpdateTypes.PrimitiveTerse) != 0)
3677 {
3678 lock (m_primTerseUpdates.SyncRoot)
3679 m_primTerseUpdates.Reprioritize(terse_update_priority_handler);
3680 }
3681 } 3627 }
3682 3628
3683 public void FlushPrimUpdates() 3629 public void FlushPrimUpdates()
3684 { 3630 {
3685 while (m_primFullUpdates.Count > 0) 3631 m_log.Debug("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
3686 { 3632
3687 ProcessPrimFullUpdates(); 3633 while (m_entityUpdates.Count > 0)
3688 } 3634 ProcessEntityUpdates(-1);
3689 while (m_primTerseUpdates.Count > 0)
3690 {
3691 ProcessPrimTerseUpdates();
3692 }
3693 while (m_avatarTerseUpdates.Count > 0)
3694 {
3695 ProcessAvatarTerseUpdates();
3696 }
3697 } 3635 }
3698 3636
3699 #endregion Primitive Packet/Data Sending Methods 3637 #endregion Primitive Packet/Data Sending Methods
@@ -3726,26 +3664,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3726 { 3664 {
3727 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 3665 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
3728 { 3666 {
3729 lock (m_avatarTerseUpdates.SyncRoot) 3667 if (m_entityUpdates.Count > 0)
3730 { 3668 ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback);
3731 if (m_avatarTerseUpdates.Count > 0)
3732 ProcessAvatarTerseUpdates();
3733 }
3734 }
3735
3736 if ((categories & ThrottleOutPacketTypeFlags.State) != 0)
3737 {
3738 lock (m_primFullUpdates.SyncRoot)
3739 {
3740 if (m_primFullUpdates.Count > 0)
3741 ProcessPrimFullUpdates();
3742 }
3743
3744 lock (m_primTerseUpdates.SyncRoot)
3745 {
3746 if (m_primTerseUpdates.Count > 0)
3747 ProcessPrimTerseUpdates();
3748 }
3749 } 3669 }
3750 3670
3751 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) 3671 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
@@ -4403,22 +4323,51 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4403 4323
4404 #region Helper Methods 4324 #region Helper Methods
4405 4325
4406 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendAvatarTerseData data) 4326 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture)
4407 { 4327 {
4408 return CreateImprovedTerseBlock(true, data.LocalID, 0, data.CollisionPlane, data.Position, data.Velocity, 4328 #region ScenePresence/SOP Handling
4409 data.Acceleration, data.Rotation, Vector3.Zero, data.TextureEntry);
4410 }
4411 4329
4412 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendPrimitiveTerseData data) 4330 bool avatar = (entity is ScenePresence);
4413 { 4331 uint localID = entity.LocalId;
4414 return CreateImprovedTerseBlock(false, data.LocalID, data.AttachPoint, Vector4.Zero, data.Position, data.Velocity, 4332 uint attachPoint;
4415 data.Acceleration, data.Rotation, data.AngularVelocity, data.TextureEntry); 4333 Vector4 collisionPlane;
4416 } 4334 Vector3 position, velocity, acceleration, angularVelocity;
4335 Quaternion rotation;
4336 byte[] textureEntry;
4337
4338 if (entity is ScenePresence)
4339 {
4340 ScenePresence presence = (ScenePresence)entity;
4341
4342 attachPoint = 0;
4343 collisionPlane = presence.CollisionPlane;
4344 position = presence.OffsetPosition;
4345 velocity = presence.Velocity;
4346 acceleration = Vector3.Zero;
4347 angularVelocity = Vector3.Zero;
4348 rotation = presence.Rotation;
4349
4350 if (sendTexture)
4351 textureEntry = presence.Appearance.Texture.GetBytes();
4352 else
4353 textureEntry = null;
4354 }
4355 else
4356 {
4357 SceneObjectPart part = (SceneObjectPart)entity;
4358
4359 attachPoint = part.AttachmentPoint;
4360 collisionPlane = Vector4.Zero;
4361 position = part.RelativePosition;
4362 velocity = part.Velocity;
4363 acceleration = part.Acceleration;
4364 angularVelocity = part.AngularVelocity;
4365 rotation = part.RotationOffset;
4366 textureEntry = part.Shape.TextureEntry;
4367 }
4368
4369 #endregion ScenePresence/SOP Handling
4417 4370
4418 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(bool avatar, uint localID, int attachPoint,
4419 Vector4 collisionPlane, Vector3 position, Vector3 velocity, Vector3 acceleration, Quaternion rotation,
4420 Vector3 angularVelocity, byte[] textureEntry)
4421 {
4422 int pos = 0; 4371 int pos = 0;
4423 byte[] data = new byte[(avatar ? 60 : 44)]; 4372 byte[] data = new byte[(avatar ? 60 : 44)];
4424 4373
@@ -4490,12 +4439,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4490 return block; 4439 return block;
4491 } 4440 }
4492 4441
4493 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(SendAvatarData data) 4442 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
4494 { 4443 {
4495 byte[] objectData = new byte[76]; 4444 byte[] objectData = new byte[76];
4496 4445
4497 Vector4.UnitW.ToBytes(objectData, 0); // TODO: Collision plane support 4446 data.CollisionPlane.ToBytes(objectData, 0);
4498 data.Position.ToBytes(objectData, 16); 4447 data.OffsetPosition.ToBytes(objectData, 16);
4499 //data.Velocity.ToBytes(objectData, 28); 4448 //data.Velocity.ToBytes(objectData, 28);
4500 //data.Acceleration.ToBytes(objectData, 40); 4449 //data.Acceleration.ToBytes(objectData, 40);
4501 data.Rotation.ToBytes(objectData, 52); 4450 data.Rotation.ToBytes(objectData, 52);
@@ -4505,12 +4454,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4505 4454
4506 update.Data = Utils.EmptyBytes; 4455 update.Data = Utils.EmptyBytes;
4507 update.ExtraParams = new byte[1]; 4456 update.ExtraParams = new byte[1];
4508 update.FullID = data.AvatarID; 4457 update.FullID = data.UUID;
4509 update.ID = data.AvatarLocalID; 4458 update.ID = data.LocalId;
4510 update.Material = (byte)Material.Flesh; 4459 update.Material = (byte)Material.Flesh;
4511 update.MediaURL = Utils.EmptyBytes; 4460 update.MediaURL = Utils.EmptyBytes;
4512 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.FirstName + "\nLastName STRING RW SV " + 4461 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
4513 data.LastName + "\nTitle STRING RW SV " + data.GroupTitle); 4462 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
4514 update.ObjectData = objectData; 4463 update.ObjectData = objectData;
4515 update.ParentID = data.ParentID; 4464 update.ParentID = data.ParentID;
4516 update.PathCurve = 16; 4465 update.PathCurve = 16;
@@ -4519,102 +4468,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4519 update.PCode = (byte)PCode.Avatar; 4468 update.PCode = (byte)PCode.Avatar;
4520 update.ProfileCurve = 1; 4469 update.ProfileCurve = 1;
4521 update.PSBlock = Utils.EmptyBytes; 4470 update.PSBlock = Utils.EmptyBytes;
4522 update.Scale = new Vector3(0.45f,0.6f,1.9f); 4471 update.Scale = new Vector3(0.45f, 0.6f, 1.9f);
4523 update.Text = Utils.EmptyBytes; 4472 update.Text = Utils.EmptyBytes;
4524 update.TextColor = new byte[4]; 4473 update.TextColor = new byte[4];
4525 update.TextureAnim = Utils.EmptyBytes; 4474 update.TextureAnim = Utils.EmptyBytes;
4526 update.TextureEntry = data.TextureEntry ?? Utils.EmptyBytes; 4475 update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
4527 update.UpdateFlags = (uint)(PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | PrimFlags.ObjectOwnerModify);//61 + (9 << 8) + (130 << 16) + (16 << 24); // TODO: Replace these numbers with PrimFlags 4476 update.UpdateFlags = (uint)(
4477 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
4478 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
4479 PrimFlags.ObjectOwnerModify);
4528 4480
4529 return update; 4481 return update;
4530 } 4482 }
4531 4483
4532 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SendPrimitiveData data) 4484 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID)
4533 { 4485 {
4534 byte[] objectData = new byte[60]; 4486 byte[] objectData = new byte[60];
4535 data.pos.ToBytes(objectData, 0); 4487 data.RelativePosition.ToBytes(objectData, 0);
4536 data.vel.ToBytes(objectData, 12); 4488 data.Velocity.ToBytes(objectData, 12);
4537 data.acc.ToBytes(objectData, 24); 4489 data.Acceleration.ToBytes(objectData, 24);
4538 data.rotation.ToBytes(objectData, 36); 4490 data.RotationOffset.ToBytes(objectData, 36);
4539 data.rvel.ToBytes(objectData, 48); 4491 data.AngularVelocity.ToBytes(objectData, 48);
4540 4492
4541 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 4493 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
4542 update.ClickAction = (byte)data.clickAction; 4494 update.ClickAction = (byte)data.ClickAction;
4543 update.CRC = 0; 4495 update.CRC = 0;
4544 update.ExtraParams = data.primShape.ExtraParams ?? Utils.EmptyBytes; 4496 update.ExtraParams = data.Shape.ExtraParams ?? Utils.EmptyBytes;
4545 update.FullID = data.objectID; 4497 update.FullID = data.UUID;
4546 update.ID = data.localID; 4498 update.ID = data.LocalId;
4547 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated 4499 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated
4548 //update.JointPivot = Vector3.Zero; 4500 //update.JointPivot = Vector3.Zero;
4549 //update.JointType = 0; 4501 //update.JointType = 0;
4550 update.Material = data.material; 4502 update.Material = data.Material;
4551 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim 4503 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
4552 if (data.attachment) 4504 if (data.IsAttachment)
4553 { 4505 {
4554 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.AssetId); 4506 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.FromItemID);
4555 update.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16)); 4507 update.State = (byte)((data.AttachmentPoint % 16) * 16 + (data.AttachmentPoint / 16));
4556 } 4508 }
4557 else 4509 else
4558 { 4510 {
4559 update.NameValue = Utils.EmptyBytes; 4511 update.NameValue = Utils.EmptyBytes;
4560 update.State = data.primShape.State; 4512 update.State = data.Shape.State;
4561 } 4513 }
4514
4562 update.ObjectData = objectData; 4515 update.ObjectData = objectData;
4563 update.ParentID = data.parentID; 4516 update.ParentID = data.ParentID;
4564 update.PathBegin = data.primShape.PathBegin; 4517 update.PathBegin = data.Shape.PathBegin;
4565 update.PathCurve = data.primShape.PathCurve; 4518 update.PathCurve = data.Shape.PathCurve;
4566 update.PathEnd = data.primShape.PathEnd; 4519 update.PathEnd = data.Shape.PathEnd;
4567 update.PathRadiusOffset = data.primShape.PathRadiusOffset; 4520 update.PathRadiusOffset = data.Shape.PathRadiusOffset;
4568 update.PathRevolutions = data.primShape.PathRevolutions; 4521 update.PathRevolutions = data.Shape.PathRevolutions;
4569 update.PathScaleX = data.primShape.PathScaleX; 4522 update.PathScaleX = data.Shape.PathScaleX;
4570 update.PathScaleY = data.primShape.PathScaleY; 4523 update.PathScaleY = data.Shape.PathScaleY;
4571 update.PathShearX = data.primShape.PathShearX; 4524 update.PathShearX = data.Shape.PathShearX;
4572 update.PathShearY = data.primShape.PathShearY; 4525 update.PathShearY = data.Shape.PathShearY;
4573 update.PathSkew = data.primShape.PathSkew; 4526 update.PathSkew = data.Shape.PathSkew;
4574 update.PathTaperX = data.primShape.PathTaperX; 4527 update.PathTaperX = data.Shape.PathTaperX;
4575 update.PathTaperY = data.primShape.PathTaperY; 4528 update.PathTaperY = data.Shape.PathTaperY;
4576 update.PathTwist = data.primShape.PathTwist; 4529 update.PathTwist = data.Shape.PathTwist;
4577 update.PathTwistBegin = data.primShape.PathTwistBegin; 4530 update.PathTwistBegin = data.Shape.PathTwistBegin;
4578 update.PCode = data.primShape.PCode; 4531 update.PCode = data.Shape.PCode;
4579 update.ProfileBegin = data.primShape.ProfileBegin; 4532 update.ProfileBegin = data.Shape.ProfileBegin;
4580 update.ProfileCurve = data.primShape.ProfileCurve; 4533 update.ProfileCurve = data.Shape.ProfileCurve;
4581 update.ProfileEnd = data.primShape.ProfileEnd; 4534 update.ProfileEnd = data.Shape.ProfileEnd;
4582 update.ProfileHollow = data.primShape.ProfileHollow; 4535 update.ProfileHollow = data.Shape.ProfileHollow;
4583 update.PSBlock = data.particleSystem ?? Utils.EmptyBytes; 4536 update.PSBlock = data.ParticleSystem ?? Utils.EmptyBytes;
4584 update.TextColor = data.color ?? Color4.Black.GetBytes(true); 4537 update.TextColor = data.GetTextColor().GetBytes(false);
4585 update.TextureAnim = data.textureanim ?? Utils.EmptyBytes; 4538 update.TextureAnim = data.TextureAnimation ?? Utils.EmptyBytes;
4586 update.TextureEntry = data.primShape.TextureEntry ?? Utils.EmptyBytes; 4539 update.TextureEntry = data.Shape.TextureEntry ?? Utils.EmptyBytes;
4587 update.Scale = data.primShape.Scale; 4540 update.Scale = data.Shape.Scale;
4588 update.Text = Util.StringToBytes256(data.text); 4541 update.Text = Util.StringToBytes256(data.Text);
4589 update.UpdateFlags = (uint)data.flags; 4542
4590 4543 #region PrimFlags
4591 if (data.SoundId != UUID.Zero) 4544
4592 { 4545 PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(recipientID, data.UUID);
4593 update.Sound = data.SoundId; 4546
4594 update.OwnerID = data.ownerID; 4547 // Don't send the CreateSelected flag to everyone
4595 update.Gain = (float)data.SoundVolume; 4548 flags &= ~PrimFlags.CreateSelected;
4549
4550 if (recipientID == data.OwnerID)
4551 {
4552 if ((data.Flags & PrimFlags.CreateSelected) != 0)
4553 {
4554 // Only send this flag once, then unset it
4555 flags |= PrimFlags.CreateSelected;
4556 data.Flags &= ~PrimFlags.CreateSelected;
4557 }
4558 }
4559
4560 update.UpdateFlags = (uint)flags;
4561
4562 #endregion PrimFlags
4563
4564 if (data.Sound != UUID.Zero)
4565 {
4566 update.Sound = data.Sound;
4567 update.OwnerID = data.OwnerID;
4568 update.Gain = (float)data.SoundGain;
4596 update.Radius = (float)data.SoundRadius; 4569 update.Radius = (float)data.SoundRadius;
4597 update.Flags = data.SoundFlags; 4570 update.Flags = data.SoundFlags;
4598 } 4571 }
4599 4572
4600 switch ((PCode)data.primShape.PCode) 4573 switch ((PCode)data.Shape.PCode)
4601 { 4574 {
4602 case PCode.Grass: 4575 case PCode.Grass:
4603 case PCode.Tree: 4576 case PCode.Tree:
4604 case PCode.NewTree: 4577 case PCode.NewTree:
4605 update.Data = new byte[] { data.primShape.State }; 4578 update.Data = new byte[] { data.Shape.State };
4606 break; 4579 break;
4607 default: 4580 default:
4608 // TODO: Support ScratchPad
4609 //if (prim.ScratchPad != null)
4610 //{
4611 // update.Data = new byte[prim.ScratchPad.Length];
4612 // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length);
4613 //}
4614 //else
4615 //{
4616 // update.Data = Utils.EmptyBytes;
4617 //}
4618 update.Data = Utils.EmptyBytes; 4581 update.Data = Utils.EmptyBytes;
4619 break; 4582 break;
4620 } 4583 }
@@ -4622,6 +4585,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4622 return update; 4585 return update;
4623 } 4586 }
4624 4587
4588 protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags)
4589 {
4590 // TODO: Implement this
4591 return null;
4592 }
4593
4625 public void SendNameReply(UUID profileId, string firstname, string lastname) 4594 public void SendNameReply(UUID profileId, string firstname, string lastname)
4626 { 4595 {
4627 UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply); 4596 UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply);
@@ -11644,7 +11613,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11644 throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); 11613 throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
11645 } 11614 }
11646 11615
11647 internal TValue Dequeue() 11616 internal bool TryDequeue(out TValue value)
11648 { 11617 {
11649 for (int i = 0; i < m_heaps.Length; ++i) 11618 for (int i = 0; i < m_heaps.Length; ++i)
11650 { 11619 {
@@ -11652,10 +11621,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11652 { 11621 {
11653 MinHeapItem item = m_heaps[i].RemoveMin(); 11622 MinHeapItem item = m_heaps[i].RemoveMin();
11654 m_lookupTable.Remove(item.LocalID); 11623 m_lookupTable.Remove(item.LocalID);
11655 return item.Value; 11624 value = item.Value;
11625 return true;
11656 } 11626 }
11657 } 11627 }
11658 throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); 11628
11629 value = default(TValue);
11630 return false;
11659 } 11631 }
11660 11632
11661 internal void Reprioritize(UpdatePriorityHandler handler) 11633 internal void Reprioritize(UpdatePriorityHandler handler)