aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/PriorityQueue.cs (renamed from OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs)132
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs196
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs82
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs68
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs7
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs80
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs142
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs66
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs9
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs13
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs73
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs6
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs48
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs10
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs42
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs237
-rw-r--r--OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs121
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs3
21 files changed, 877 insertions, 481 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Framework/PriorityQueue.cs
index b62ec07..3e6fdaa 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs
+++ b/OpenSim/Framework/PriorityQueue.cs
@@ -34,50 +34,81 @@ using OpenSim.Framework;
34using OpenSim.Framework.Client; 34using OpenSim.Framework.Client;
35using log4net; 35using log4net;
36 36
37namespace OpenSim.Region.ClientStack.LindenUDP 37namespace OpenSim.Framework
38{ 38{
39 public class PriorityQueue 39 public class PriorityQueue
40 { 40 {
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 42
43 internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); 43 public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
44 44
45 // Heap[0] for self updates 45 /// <summary>
46 // Heap[1..12] for entity updates 46 /// Total number of queues (priorities) available
47 /// </summary>
48 public const uint NumberOfQueues = 12;
47 49
48 internal const uint m_numberOfQueues = 12; 50 /// <summary>
51 /// Number of queuest (priorities) that are processed immediately
52 /// </summary.
53 public const uint NumberOfImmediateQueues = 2;
49 54
50 private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[m_numberOfQueues]; 55 private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues];
51 private Dictionary<uint, LookupItem> m_lookupTable; 56 private Dictionary<uint, LookupItem> m_lookupTable;
57
58 // internal state used to ensure the deqeues are spread across the priority
59 // queues "fairly". queuecounts is the amount to pull from each queue in
60 // each pass. weighted towards the higher priority queues
52 private uint m_nextQueue = 0; 61 private uint m_nextQueue = 0;
62 private uint m_countFromQueue = 0;
63 private uint[] m_queueCounts = { 8, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1 };
64
65 // next request is a counter of the number of updates queued, it provides
66 // a total ordering on the updates coming through the queue and is more
67 // lightweight (and more discriminating) than tick count
53 private UInt64 m_nextRequest = 0; 68 private UInt64 m_nextRequest = 0;
54 69
70 /// <summary>
71 /// Lock for enqueue and dequeue operations on the priority queue
72 /// </summary>
55 private object m_syncRoot = new object(); 73 private object m_syncRoot = new object();
56 public object SyncRoot { 74 public object SyncRoot {
57 get { return this.m_syncRoot; } 75 get { return this.m_syncRoot; }
58 } 76 }
59 77
60 internal PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { } 78#region constructor
79 public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
61 80
62 internal PriorityQueue(int capacity) 81 public PriorityQueue(int capacity)
63 { 82 {
64 m_lookupTable = new Dictionary<uint, LookupItem>(capacity); 83 m_lookupTable = new Dictionary<uint, LookupItem>(capacity);
65 84
66 for (int i = 0; i < m_heaps.Length; ++i) 85 for (int i = 0; i < m_heaps.Length; ++i)
67 m_heaps[i] = new MinHeap<MinHeapItem>(capacity); 86 m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
87
88 m_nextQueue = NumberOfImmediateQueues;
89 m_countFromQueue = m_queueCounts[m_nextQueue];
68 } 90 }
91#endregion Constructor
69 92
70 internal int Count 93#region PublicMethods
94 /// <summary>
95 /// Return the number of items in the queues
96 /// </summary>
97 public int Count
71 { 98 {
72 get 99 get
73 { 100 {
74 int count = 0; 101 int count = 0;
75 for (int i = 0; i < m_heaps.Length; ++i) 102 for (int i = 0; i < m_heaps.Length; ++i)
76 count += m_heaps[i].Count; 103 count += m_heaps[i].Count;
104
77 return count; 105 return count;
78 } 106 }
79 } 107 }
80 108
109 /// <summary>
110 /// Enqueue an item into the specified priority queue
111 /// </summary>
81 public bool Enqueue(uint pqueue, IEntityUpdate value) 112 public bool Enqueue(uint pqueue, IEntityUpdate value)
82 { 113 {
83 LookupItem lookup; 114 LookupItem lookup;
@@ -91,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
91 lookup.Heap.Remove(lookup.Handle); 122 lookup.Heap.Remove(lookup.Handle);
92 } 123 }
93 124
94 pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); 125 pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
95 lookup.Heap = m_heaps[pqueue]; 126 lookup.Heap = m_heaps[pqueue];
96 lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); 127 lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
97 m_lookupTable[localid] = lookup; 128 m_lookupTable[localid] = lookup;
@@ -99,20 +130,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 return true; 130 return true;
100 } 131 }
101 132
102 internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) 133 /// <summary>
134 /// Remove an item from one of the queues. Specifically, it removes the
135 /// oldest item from the next queue in order to provide fair access to
136 /// all of the queues
137 /// </summary>
138 public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
103 { 139 {
104 for (int i = 0; i < m_numberOfQueues; ++i) 140 // If there is anything in priority queue 0, return it first no
141 // matter what else. Breaks fairness. But very useful.
142 for (int iq = 0; iq < NumberOfImmediateQueues; iq++)
105 { 143 {
106 // To get the fair queing, we cycle through each of the 144 if (m_heaps[iq].Count > 0)
107 // queues when finding an element to dequeue, this code
108 // assumes that the distribution of updates in the queues
109 // is polynomial, probably quadractic (eg distance of PI * R^2)
110 uint h = (uint)((m_nextQueue + i) % m_numberOfQueues);
111 if (m_heaps[h].Count > 0)
112 { 145 {
113 m_nextQueue = (uint)((h + 1) % m_numberOfQueues); 146 MinHeapItem item = m_heaps[iq].RemoveMin();
147 m_lookupTable.Remove(item.Value.Entity.LocalId);
148 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
149 value = item.Value;
114 150
115 MinHeapItem item = m_heaps[h].RemoveMin(); 151 return true;
152 }
153 }
154
155 // To get the fair queing, we cycle through each of the
156 // queues when finding an element to dequeue.
157 // We pull (NumberOfQueues - QueueIndex) items from each queue in order
158 // to give lower numbered queues a higher priority and higher percentage
159 // of the bandwidth.
160
161 // Check for more items to be pulled from the current queue
162 if (m_heaps[m_nextQueue].Count > 0 && m_countFromQueue > 0)
163 {
164 m_countFromQueue--;
165
166 MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
167 m_lookupTable.Remove(item.Value.Entity.LocalId);
168 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
169 value = item.Value;
170
171 return true;
172 }
173
174 // Find the next non-immediate queue with updates in it
175 for (int i = 0; i < NumberOfQueues; ++i)
176 {
177 m_nextQueue = (uint)((m_nextQueue + 1) % NumberOfQueues);
178 m_countFromQueue = m_queueCounts[m_nextQueue];
179
180 // if this is one of the immediate queues, just skip it
181 if (m_nextQueue < NumberOfImmediateQueues)
182 continue;
183
184 if (m_heaps[m_nextQueue].Count > 0)
185 {
186 m_countFromQueue--;
187
188 MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
116 m_lookupTable.Remove(item.Value.Entity.LocalId); 189 m_lookupTable.Remove(item.Value.Entity.LocalId);
117 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); 190 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
118 value = item.Value; 191 value = item.Value;
@@ -126,7 +199,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 return false; 199 return false;
127 } 200 }
128 201
129 internal void Reprioritize(UpdatePriorityHandler handler) 202 /// <summary>
203 /// Reapply the prioritization function to each of the updates currently
204 /// stored in the priority queues.
205 /// </summary
206 public void Reprioritize(UpdatePriorityHandler handler)
130 { 207 {
131 MinHeapItem item; 208 MinHeapItem item;
132 foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values)) 209 foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values))
@@ -140,7 +217,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
140 { 217 {
141 // unless the priority queue has changed, there is no need to modify 218 // unless the priority queue has changed, there is no need to modify
142 // the entry 219 // the entry
143 pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); 220 pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
144 if (pqueue != item.PriorityQueue) 221 if (pqueue != item.PriorityQueue)
145 { 222 {
146 lookup.Heap.Remove(lookup.Handle); 223 lookup.Heap.Remove(lookup.Handle);
@@ -161,17 +238,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 } 238 }
162 } 239 }
163 240
241 /// <summary>
242 /// </summary>
164 public override string ToString() 243 public override string ToString()
165 { 244 {
166 string s = ""; 245 string s = "";
167 for (int i = 0; i < m_numberOfQueues; i++) 246 for (int i = 0; i < NumberOfQueues; i++)
168 { 247 s += String.Format("{0,7} ",m_heaps[i].Count);
169 if (s != "") s += ",";
170 s += m_heaps[i].Count.ToString();
171 }
172 return s; 248 return s;
173 } 249 }
174 250
251#endregion PublicMethods
252
175#region MinHeapItem 253#region MinHeapItem
176 private struct MinHeapItem : IComparable<MinHeapItem> 254 private struct MinHeapItem : IComparable<MinHeapItem>
177 { 255 {
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 0f7f666..43903ce 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -385,6 +385,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
385 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 385 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
386 386
387 /// <summary> 387 /// <summary>
388 /// Entity update queues
389 /// </summary>
390 public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } }
391
392 /// <summary>
388 /// First name of the agent/avatar represented by the client 393 /// First name of the agent/avatar represented by the client
389 /// </summary> 394 /// </summary>
390 public string FirstName { get { return m_firstName; } } 395 public string FirstName { get { return m_firstName; } }
@@ -3561,6 +3566,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3561 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3566 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3562 } 3567 }
3563 3568
3569 /// <summary>
3570 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3571 /// We will update the priority and put it in the correct queue, merging update flags
3572 /// with any other updates that may be queued for the same entity.
3573 /// The original update time is used for the merged update.
3574 /// </summary>
3575 private void ResendPrimUpdate(EntityUpdate update)
3576 {
3577 // If the update exists in priority queue, it will be updated.
3578 // If it does not exist then it will be added with the current (rather than its original) priority
3579 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3580
3581 lock (m_entityUpdates.SyncRoot)
3582 m_entityUpdates.Enqueue(priority, update);
3583 }
3584
3585 /// <summary>
3586 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3587 /// We will update the priority and put it in the correct queue, merging update flags
3588 /// with any other updates that may be queued for the same entity.
3589 /// The original update time is used for the merged update.
3590 /// </summary>
3591 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
3592 {
3593 // m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime);
3594
3595 // Remove the update packet from the list of packets waiting for acknowledgement
3596 // because we are requeuing the list of updates. They will be resent in new packets
3597 // with the most recent state and priority.
3598 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3599
3600 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3601 Interlocked.Increment(ref m_udpClient.PacketsResent);
3602
3603 foreach (EntityUpdate update in updates)
3604 ResendPrimUpdate(update);
3605 }
3606
3564 private void ProcessEntityUpdates(int maxUpdates) 3607 private void ProcessEntityUpdates(int maxUpdates)
3565 { 3608 {
3566 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3609 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3568,6 +3611,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3568 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3611 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>>(); 3612 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3570 3613
3614 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3615 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3616 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3617 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3618
3571 // Check to see if this is a flush 3619 // Check to see if this is a flush
3572 if (maxUpdates <= 0) 3620 if (maxUpdates <= 0)
3573 { 3621 {
@@ -3583,7 +3631,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3583 float avgTimeDilation = 1.0f; 3631 float avgTimeDilation = 1.0f;
3584 IEntityUpdate iupdate; 3632 IEntityUpdate iupdate;
3585 Int32 timeinqueue; // this is just debugging code & can be dropped later 3633 Int32 timeinqueue; // this is just debugging code & can be dropped later
3586 3634
3587 while (updatesThisCall < maxUpdates) 3635 while (updatesThisCall < maxUpdates)
3588 { 3636 {
3589 lock (m_entityUpdates.SyncRoot) 3637 lock (m_entityUpdates.SyncRoot)
@@ -3688,24 +3736,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3688 if (update.Entity is ScenePresence) 3736 if (update.Entity is ScenePresence)
3689 { 3737 {
3690 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); 3738 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3739 objectUpdates.Value.Add(update);
3691 } 3740 }
3692 else 3741 else
3693 { 3742 {
3694 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); 3743 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3744 objectUpdates.Value.Add(update);
3695 } 3745 }
3696 } 3746 }
3697 else if (!canUseImproved) 3747 else if (!canUseImproved)
3698 { 3748 {
3699 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3749 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3750 compressedUpdates.Value.Add(update);
3700 } 3751 }
3701 else 3752 else
3702 { 3753 {
3703 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3754 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3755 {
3704 // Self updates go into a special list 3756 // Self updates go into a special list
3705 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3757 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3758 terseAgentUpdates.Value.Add(update);
3759 }
3706 else 3760 else
3761 {
3707 // Everything else goes here 3762 // Everything else goes here
3708 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3763 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3764 terseUpdates.Value.Add(update);
3765 }
3709 } 3766 }
3710 3767
3711 #endregion Block Construction 3768 #endregion Block Construction
@@ -3713,28 +3770,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3713 3770
3714 3771
3715 #region Packet Sending 3772 #region Packet Sending
3716
3717 //const float TIME_DILATION = 1.0f;
3718
3719
3720 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3773 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3721 3774
3722 if (terseAgentUpdateBlocks.IsValueCreated) 3775 if (terseAgentUpdateBlocks.IsValueCreated)
3723 { 3776 {
3724 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3777 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3725 3778
3726 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3779 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3727 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3780 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3728 packet.RegionData.TimeDilation = timeDilation; 3781 packet.RegionData.TimeDilation = timeDilation;
3729 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3782 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3730 3783
3731 for (int i = 0; i < blocks.Count; i++) 3784 for (int i = 0; i < blocks.Count; i++)
3732 packet.ObjectData[i] = blocks[i]; 3785 packet.ObjectData[i] = blocks[i];
3733 3786 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3734 3787 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); });
3735 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3736 } 3788 }
3737 3789
3738 if (objectUpdateBlocks.IsValueCreated) 3790 if (objectUpdateBlocks.IsValueCreated)
3739 { 3791 {
3740 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3792 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
@@ -3746,8 +3798,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3746 3798
3747 for (int i = 0; i < blocks.Count; i++) 3799 for (int i = 0; i < blocks.Count; i++)
3748 packet.ObjectData[i] = blocks[i]; 3800 packet.ObjectData[i] = blocks[i];
3749 3801 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3750 OutPacket(packet, ThrottleOutPacketType.Task, true); 3802 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
3751 } 3803 }
3752 3804
3753 if (compressedUpdateBlocks.IsValueCreated) 3805 if (compressedUpdateBlocks.IsValueCreated)
@@ -3761,10 +3813,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3761 3813
3762 for (int i = 0; i < blocks.Count; i++) 3814 for (int i = 0; i < blocks.Count; i++)
3763 packet.ObjectData[i] = blocks[i]; 3815 packet.ObjectData[i] = blocks[i];
3764 3816 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3765 OutPacket(packet, ThrottleOutPacketType.Task, true); 3817 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
3766 } 3818 }
3767 3819
3768 if (terseUpdateBlocks.IsValueCreated) 3820 if (terseUpdateBlocks.IsValueCreated)
3769 { 3821 {
3770 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 3822 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
@@ -3776,8 +3828,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3776 3828
3777 for (int i = 0; i < blocks.Count; i++) 3829 for (int i = 0; i < blocks.Count; i++)
3778 packet.ObjectData[i] = blocks[i]; 3830 packet.ObjectData[i] = blocks[i];
3779 3831 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3780 OutPacket(packet, ThrottleOutPacketType.Task, true); 3832 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
3781 } 3833 }
3782 } 3834 }
3783 3835
@@ -3969,7 +4021,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3969 { 4021 {
3970 SendFamilyProps = SendFamilyProps || update.SendFamilyProps; 4022 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
3971 SendObjectProps = SendObjectProps || update.SendObjectProps; 4023 SendObjectProps = SendObjectProps || update.SendObjectProps;
3972 Flags |= update.Flags; 4024 // other properties may need to be updated by base class
4025 base.Update(update);
3973 } 4026 }
3974 } 4027 }
3975 4028
@@ -3980,6 +4033,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3980 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); 4033 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
3981 } 4034 }
3982 4035
4036 private void ResendPropertyUpdate(ObjectPropertyUpdate update)
4037 {
4038 uint priority = 0;
4039 lock (m_entityProps.SyncRoot)
4040 m_entityProps.Enqueue(priority, update);
4041 }
4042
4043 private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket)
4044 {
4045 // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime);
4046
4047 // Remove the update packet from the list of packets waiting for acknowledgement
4048 // because we are requeuing the list of updates. They will be resent in new packets
4049 // with the most recent state.
4050 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
4051
4052 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4053 Interlocked.Increment(ref m_udpClient.PacketsResent);
4054
4055 foreach (ObjectPropertyUpdate update in updates)
4056 ResendPropertyUpdate(update);
4057 }
4058
3983 public void SendObjectPropertiesReply(ISceneEntity entity) 4059 public void SendObjectPropertiesReply(ISceneEntity entity)
3984 { 4060 {
3985 uint priority = 0; // time based ordering only 4061 uint priority = 0; // time based ordering only
@@ -3995,6 +4071,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3995 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = 4071 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
3996 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); 4072 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
3997 4073
4074 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
4075 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4076
4077 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
4078 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4079
3998 IEntityUpdate iupdate; 4080 IEntityUpdate iupdate;
3999 Int32 timeinqueue; // this is just debugging code & can be dropped later 4081 Int32 timeinqueue; // this is just debugging code & can be dropped later
4000 4082
@@ -4013,6 +4095,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4013 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4095 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4014 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); 4096 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
4015 objectFamilyBlocks.Value.Add(objPropDB); 4097 objectFamilyBlocks.Value.Add(objPropDB);
4098 familyUpdates.Value.Add(update);
4016 } 4099 }
4017 } 4100 }
4018 4101
@@ -4023,6 +4106,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4023 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4106 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4024 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); 4107 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
4025 objectPropertiesBlocks.Value.Add(objPropDB); 4108 objectPropertiesBlocks.Value.Add(objPropDB);
4109 propertyUpdates.Value.Add(update);
4026 } 4110 }
4027 } 4111 }
4028 4112
@@ -4030,12 +4114,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4030 } 4114 }
4031 4115
4032 4116
4033 Int32 ppcnt = 0; 4117 // Int32 ppcnt = 0;
4034 Int32 pbcnt = 0; 4118 // Int32 pbcnt = 0;
4035 4119
4036 if (objectPropertiesBlocks.IsValueCreated) 4120 if (objectPropertiesBlocks.IsValueCreated)
4037 { 4121 {
4038 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; 4122 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
4123 List<ObjectPropertyUpdate> updates = propertyUpdates.Value;
4039 4124
4040 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4125 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4041 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; 4126 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
@@ -4043,28 +4128,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4043 packet.ObjectData[i] = blocks[i]; 4128 packet.ObjectData[i] = blocks[i];
4044 4129
4045 packet.Header.Zerocoded = true; 4130 packet.Header.Zerocoded = true;
4046 OutPacket(packet, ThrottleOutPacketType.Task, true);
4047 4131
4048 pbcnt += blocks.Count; 4132 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4049 ppcnt++; 4133 // of the object rather than the properties when the packet was created
4134 OutPacket(packet, ThrottleOutPacketType.Task, true,
4135 delegate(OutgoingPacket oPacket)
4136 {
4137 ResendPropertyUpdates(updates, oPacket);
4138 });
4139
4140 // pbcnt += blocks.Count;
4141 // ppcnt++;
4050 } 4142 }
4051 4143
4052 Int32 fpcnt = 0; 4144 // Int32 fpcnt = 0;
4053 Int32 fbcnt = 0; 4145 // Int32 fbcnt = 0;
4054 4146
4055 if (objectFamilyBlocks.IsValueCreated) 4147 if (objectFamilyBlocks.IsValueCreated)
4056 { 4148 {
4057 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; 4149 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
4058 4150
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... 4151 // one packet per object block... uggh...
4069 for (int i = 0; i < blocks.Count; i++) 4152 for (int i = 0; i < blocks.Count; i++)
4070 { 4153 {
@@ -4073,10 +4156,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4073 4156
4074 packet.ObjectData = blocks[i]; 4157 packet.ObjectData = blocks[i];
4075 packet.Header.Zerocoded = true; 4158 packet.Header.Zerocoded = true;
4076 OutPacket(packet, ThrottleOutPacketType.Task);
4077 4159
4078 fpcnt++; 4160 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4079 fbcnt++; 4161 // of the object rather than the properties when the packet was created
4162 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4163 updates.Add(familyUpdates.Value[i]);
4164 OutPacket(packet, ThrottleOutPacketType.Task, true,
4165 delegate(OutgoingPacket oPacket)
4166 {
4167 ResendPropertyUpdates(updates, oPacket);
4168 });
4169
4170 // fpcnt++;
4171 // fbcnt++;
4080 } 4172 }
4081 4173
4082 } 4174 }
@@ -4113,7 +4205,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4113 4205
4114 return block; 4206 return block;
4115 } 4207 }
4116 4208
4117 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) 4209 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
4118 { 4210 {
4119 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4211 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
@@ -11336,7 +11428,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11336 /// <returns></returns> 11428 /// <returns></returns>
11337 public byte[] GetThrottlesPacked(float multiplier) 11429 public byte[] GetThrottlesPacked(float multiplier)
11338 { 11430 {
11339 return m_udpClient.GetThrottlesPacked(); 11431 return m_udpClient.GetThrottlesPacked(multiplier);
11340 } 11432 }
11341 11433
11342 /// <summary> 11434 /// <summary>
@@ -11371,6 +11463,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11371 /// handles splitting manually</param> 11463 /// handles splitting manually</param>
11372 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) 11464 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
11373 { 11465 {
11466 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
11467 }
11468
11469 /// <summary>
11470 /// This is the starting point for sending a simulator packet out to the client
11471 /// </summary>
11472 /// <param name="packet">Packet to send</param>
11473 /// <param name="throttlePacketType">Throttling category for the packet</param>
11474 /// <param name="doAutomaticSplitting">True to automatically split oversized
11475 /// packets (the default), or false to disable splitting if the calling code
11476 /// handles splitting manually</param>
11477 /// <param name="method">The method to be called in the event this packet is reliable
11478 /// and unacknowledged. The server will provide normal resend capability if you do not
11479 /// provide your own method.</param>
11480 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
11481 {
11374 if (m_debugPacketLevel > 0) 11482 if (m_debugPacketLevel > 0)
11375 { 11483 {
11376 bool logPacket = true; 11484 bool logPacket = true;
@@ -11396,7 +11504,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11396 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); 11504 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type);
11397 } 11505 }
11398 11506
11399 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); 11507 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11400 } 11508 }
11401 11509
11402 public bool AddMoney(int debit) 11510 public bool AddMoney(int debit)
@@ -11527,7 +11635,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11527 11635
11528 info.userEP = m_userEndPoint; 11636 info.userEP = m_userEndPoint;
11529 info.proxyEP = null; 11637 info.proxyEP = null;
11530 info.agentcircuit = new sAgentCircuitData(RequestClientInfo()); 11638 info.agentcircuit = RequestClientInfo();
11531 11639
11532 return info; 11640 return info;
11533 } 11641 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 7be8a0a..ca5501d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -135,7 +135,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
135 private int m_nextOnQueueEmpty = 1; 135 private int m_nextOnQueueEmpty = 1;
136 136
137 /// <summary>Throttle bucket for this agent's connection</summary> 137 /// <summary>Throttle bucket for this agent's connection</summary>
138 private readonly TokenBucket m_throttleClient; 138 private readonly AdaptiveTokenBucket m_throttleClient;
139 public AdaptiveTokenBucket FlowThrottle
140 {
141 get { return m_throttleClient; }
142 }
143
139 /// <summary>Throttle bucket for this agent's connection</summary> 144 /// <summary>Throttle bucket for this agent's connection</summary>
140 private readonly TokenBucket m_throttleCategory; 145 private readonly TokenBucket m_throttleCategory;
141 /// <summary>Throttle buckets for each packet category</summary> 146 /// <summary>Throttle buckets for each packet category</summary>
@@ -176,9 +181,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
176 m_maxRTO = maxRTO; 181 m_maxRTO = maxRTO;
177 182
178 // Create a token bucket throttle for this client that has the scene token bucket as a parent 183 // Create a token bucket throttle for this client that has the scene token bucket as a parent
179 m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); 184 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
180 // Create a token bucket throttle for the total categary with the client bucket as a throttle 185 // Create a token bucket throttle for the total categary with the client bucket as a throttle
181 m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); 186 m_throttleCategory = new TokenBucket(m_throttleClient, 0);
182 // Create an array of token buckets for this clients different throttle categories 187 // Create an array of token buckets for this clients different throttle categories
183 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 188 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
184 189
@@ -189,7 +194,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
189 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 194 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
190 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 195 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
191 // Initialize the token buckets that control the throttling for each category 196 // Initialize the token buckets that control the throttling for each category
192 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); 197 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
193 } 198 }
194 199
195 // Default the retransmission timeout to three seconds 200 // Default the retransmission timeout to three seconds
@@ -223,26 +228,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
223 /// <returns>Information about the client connection</returns> 228 /// <returns>Information about the client connection</returns>
224 public ClientInfo GetClientInfo() 229 public ClientInfo GetClientInfo()
225 { 230 {
226///<mic>
227 TokenBucket tb;
228
229 tb = m_throttleClient.Parent;
230 m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT");
231
232 tb = m_throttleClient;
233 m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT");
234
235 tb = m_throttleCategory;
236 m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY");
237
238 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
239 {
240 tb = m_throttleCategories[i];
241 m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET");
242 }
243
244///</mic>
245
246 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 231 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
247 // of pending and needed ACKs for every client every time some method wants information about 232 // of pending and needed ACKs for every client every time some method wants information about
248 // this connection is a recipe for poor performance 233 // this connection is a recipe for poor performance
@@ -254,12 +239,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
254 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 239 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
255 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 240 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
256 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 241 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
257 // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
258 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 242 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
259 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 243 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
260 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 244 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
261 info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + 245 info.totalThrottle = (int)m_throttleCategory.DripRate;
262 info.taskThrottle + info.assetThrottle + info.textureThrottle;
263 246
264 return info; 247 return info;
265 } 248 }
@@ -346,8 +329,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
346 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 329 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
347 // State is a subcategory of task that we allocate a percentage to 330 // State is a subcategory of task that we allocate a percentage to
348 int state = 0; 331 int state = 0;
349 // int state = (int)((float)task * STATE_TASK_PERCENTAGE);
350 // task -= state;
351 332
352 // Make sure none of the throttles are set below our packet MTU, 333 // Make sure none of the throttles are set below our packet MTU,
353 // otherwise a throttle could become permanently clogged 334 // otherwise a throttle could become permanently clogged
@@ -358,19 +339,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
358 task = Math.Max(task, LLUDPServer.MTU); 339 task = Math.Max(task, LLUDPServer.MTU);
359 texture = Math.Max(texture, LLUDPServer.MTU); 340 texture = Math.Max(texture, LLUDPServer.MTU);
360 asset = Math.Max(asset, LLUDPServer.MTU); 341 asset = Math.Max(asset, LLUDPServer.MTU);
361 state = Math.Max(state, LLUDPServer.MTU);
362
363 int total = resend + land + wind + cloud + task + texture + asset + state;
364 342
365 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}", 343 //int total = resend + land + wind + cloud + task + texture + asset;
366 // AgentID, resend, land, wind, cloud, task, texture, asset, state, total); 344 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
345 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
367 346
368 // Update the token buckets with new throttle values 347 // Update the token buckets with new throttle values
369 TokenBucket bucket; 348 TokenBucket bucket;
370 349
371 bucket = m_throttleCategory;
372 bucket.RequestedDripRate = total;
373
374 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 350 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
375 bucket.RequestedDripRate = resend; 351 bucket.RequestedDripRate = resend;
376 352
@@ -399,22 +375,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
399 m_packedThrottles = null; 375 m_packedThrottles = null;
400 } 376 }
401 377
402 public byte[] GetThrottlesPacked() 378 public byte[] GetThrottlesPacked(float multiplier)
403 { 379 {
404 byte[] data = m_packedThrottles; 380 byte[] data = m_packedThrottles;
405 381
406 if (data == null) 382 if (data == null)
407 { 383 {
384 float rate;
385
408 data = new byte[7 * 4]; 386 data = new byte[7 * 4];
409 int i = 0; 387 int i = 0;
410 388
411 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; 389 // multiply by 8 to convert bytes back to bits
412 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; 390 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier;
413 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; 391 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
414 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; 392
415 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; 393 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier;
416 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; 394 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
417 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; 395
396 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier;
397 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
398
399 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier;
400 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
401
402 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier;
403 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
404
405 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier;
406 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
407
408 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier;
409 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
418 410
419 m_packedThrottles = data; 411 m_packedThrottles = data;
420 } 412 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index d08b25f..aff90c5 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -297,7 +297,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
297 delegate(IClientAPI client) 297 delegate(IClientAPI client)
298 { 298 {
299 if (client is LLClientView) 299 if (client is LLClientView)
300 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); 300 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
301 } 301 }
302 ); 302 );
303 } 303 }
@@ -309,7 +309,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
309 delegate(IClientAPI client) 309 delegate(IClientAPI client)
310 { 310 {
311 if (client is LLClientView) 311 if (client is LLClientView)
312 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); 312 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
313 } 313 }
314 ); 314 );
315 } 315 }
@@ -322,7 +322,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
322 /// <param name="packet"></param> 322 /// <param name="packet"></param>
323 /// <param name="category"></param> 323 /// <param name="category"></param>
324 /// <param name="allowSplitting"></param> 324 /// <param name="allowSplitting"></param>
325 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) 325 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
326 { 326 {
327 // CoarseLocationUpdate packets cannot be split in an automated way 327 // CoarseLocationUpdate packets cannot be split in an automated way
328 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 328 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@@ -339,13 +339,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
339 for (int i = 0; i < packetCount; i++) 339 for (int i = 0; i < packetCount; i++)
340 { 340 {
341 byte[] data = datas[i]; 341 byte[] data = datas[i];
342 SendPacketData(udpClient, data, packet.Type, category); 342 SendPacketData(udpClient, data, packet.Type, category, method);
343 } 343 }
344 } 344 }
345 else 345 else
346 { 346 {
347 byte[] data = packet.ToBytes(); 347 byte[] data = packet.ToBytes();
348 SendPacketData(udpClient, data, packet.Type, category); 348 SendPacketData(udpClient, data, packet.Type, category, method);
349 } 349 }
350 } 350 }
351 351
@@ -356,7 +356,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
356 /// <param name="data"></param> 356 /// <param name="data"></param>
357 /// <param name="type"></param> 357 /// <param name="type"></param>
358 /// <param name="category"></param> 358 /// <param name="category"></param>
359 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) 359 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
360 { 360 {
361 int dataLength = data.Length; 361 int dataLength = data.Length;
362 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; 362 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
@@ -411,7 +411,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
411 411
412 #region Queue or Send 412 #region Queue or Send
413 413
414 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); 414 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
415 // If we were not provided a method for handling unacked, use the UDPServer default method
416 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
415 417
416 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will 418 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
417 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 419 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
@@ -445,7 +447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
445 packet.Header.Reliable = false; 447 packet.Header.Reliable = false;
446 packet.Packets = blocks.ToArray(); 448 packet.Packets = blocks.ToArray();
447 449
448 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); 450 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
449 } 451 }
450 } 452 }
451 453
@@ -458,17 +460,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
458 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit 460 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
459 pc.PingID.OldestUnacked = 0; 461 pc.PingID.OldestUnacked = 0;
460 462
461 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); 463 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
462 } 464 }
463 465
464 public void CompletePing(LLUDPClient udpClient, byte pingID) 466 public void CompletePing(LLUDPClient udpClient, byte pingID)
465 { 467 {
466 CompletePingCheckPacket completePing = new CompletePingCheckPacket(); 468 CompletePingCheckPacket completePing = new CompletePingCheckPacket();
467 completePing.PingID.PingID = pingID; 469 completePing.PingID.PingID = pingID;
468 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); 470 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
469 } 471 }
470 472
471 public void ResendUnacked(LLUDPClient udpClient) 473 public void HandleUnacked(LLUDPClient udpClient)
472 { 474 {
473 if (!udpClient.IsConnected) 475 if (!udpClient.IsConnected)
474 return; 476 return;
@@ -488,31 +490,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
488 490
489 if (expiredPackets != null) 491 if (expiredPackets != null)
490 { 492 {
491 //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); 493 //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
492
493 // Exponential backoff of the retransmission timeout 494 // Exponential backoff of the retransmission timeout
494 udpClient.BackoffRTO(); 495 udpClient.BackoffRTO();
496 for (int i = 0; i < expiredPackets.Count; ++i)
497 expiredPackets[i].UnackedMethod(expiredPackets[i]);
498 }
499 }
495 500
496 // Resend packets 501 public void ResendUnacked(OutgoingPacket outgoingPacket)
497 for (int i = 0; i < expiredPackets.Count; i++) 502 {
498 { 503 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
499 OutgoingPacket outgoingPacket = expiredPackets[i]; 504 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
500
501 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
502 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
503 505
504 // Set the resent flag 506 // Set the resent flag
505 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 507 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
506 outgoingPacket.Category = ThrottleOutPacketType.Resend; 508 outgoingPacket.Category = ThrottleOutPacketType.Resend;
507 509
508 // Bump up the resend count on this packet 510 // Bump up the resend count on this packet
509 Interlocked.Increment(ref outgoingPacket.ResendCount); 511 Interlocked.Increment(ref outgoingPacket.ResendCount);
510 512
511 // Requeue or resend the packet 513 // Requeue or resend the packet
512 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) 514 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
513 SendPacketFinal(outgoingPacket); 515 SendPacketFinal(outgoingPacket);
514 }
515 }
516 } 516 }
517 517
518 public void Flush(LLUDPClient udpClient) 518 public void Flush(LLUDPClient udpClient)
@@ -672,7 +672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
672 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 672 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
673 { 673 {
674 for (int i = 0; i < packet.Header.AckList.Length; i++) 674 for (int i = 0; i < packet.Header.AckList.Length; i++)
675 udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent); 675 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
676 } 676 }
677 677
678 // Handle PacketAck packets 678 // Handle PacketAck packets
@@ -681,7 +681,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
681 PacketAckPacket ackPacket = (PacketAckPacket)packet; 681 PacketAckPacket ackPacket = (PacketAckPacket)packet;
682 682
683 for (int i = 0; i < ackPacket.Packets.Length; i++) 683 for (int i = 0; i < ackPacket.Packets.Length; i++)
684 udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent); 684 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
685 685
686 // We don't need to do anything else with PacketAck packets 686 // We don't need to do anything else with PacketAck packets
687 return; 687 return;
@@ -1096,7 +1096,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1096 if (udpClient.IsConnected) 1096 if (udpClient.IsConnected)
1097 { 1097 {
1098 if (m_resendUnacked) 1098 if (m_resendUnacked)
1099 ResendUnacked(udpClient); 1099 HandleUnacked(udpClient);
1100 1100
1101 if (m_sendAcks) 1101 if (m_sendAcks)
1102 SendAcks(udpClient); 1102 SendAcks(udpClient);
@@ -1152,7 +1152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1152 nticksUnack++; 1152 nticksUnack++;
1153 watch2.Start(); 1153 watch2.Start();
1154 1154
1155 ResendUnacked(udpClient); 1155 HandleUnacked(udpClient);
1156 1156
1157 watch2.Stop(); 1157 watch2.Stop();
1158 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); 1158 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
index 1a1a1cb..76c6c14 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
@@ -31,6 +31,8 @@ using OpenMetaverse;
31 31
32namespace OpenSim.Region.ClientStack.LindenUDP 32namespace OpenSim.Region.ClientStack.LindenUDP
33{ 33{
34
35 public delegate void UnackedPacketMethod(OutgoingPacket oPacket);
34 /// <summary> 36 /// <summary>
35 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is 37 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
36 /// destined for, along with the serialized packet data, sequence number 38 /// destined for, along with the serialized packet data, sequence number
@@ -52,6 +54,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 public int TickCount; 54 public int TickCount;
53 /// <summary>Category this packet belongs to</summary> 55 /// <summary>Category this packet belongs to</summary>
54 public ThrottleOutPacketType Category; 56 public ThrottleOutPacketType Category;
57 /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary>
58 public UnackedPacketMethod UnackedMethod;
55 59
56 /// <summary> 60 /// <summary>
57 /// Default constructor 61 /// Default constructor
@@ -60,11 +64,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
60 /// <param name="buffer">Serialized packet data. If the flags or sequence number 64 /// <param name="buffer">Serialized packet data. If the flags or sequence number
61 /// need to be updated, they will be injected directly into this binary buffer</param> 65 /// need to be updated, they will be injected directly into this binary buffer</param>
62 /// <param name="category">Throttling category for this packet</param> 66 /// <param name="category">Throttling category for this packet</param>
63 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category) 67 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
64 { 68 {
65 Client = client; 69 Client = client;
66 Buffer = buffer; 70 Buffer = buffer;
67 Category = category; 71 Category = category;
72 UnackedMethod = method;
68 } 73 }
69 } 74 }
70} 75}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
index aaf6e26..c9aac0b 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
@@ -52,30 +52,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 public int Texture; 52 public int Texture;
53 /// <summary>Drip rate for asset packets</summary> 53 /// <summary>Drip rate for asset packets</summary>
54 public int Asset; 54 public int Asset;
55 /// <summary>Drip rate for state packets</summary> 55
56 public int State;
57 /// <summary>Drip rate for the parent token bucket</summary> 56 /// <summary>Drip rate for the parent token bucket</summary>
58 public int Total; 57 public int Total;
59 58
60 /// <summary>Maximum burst rate for resent packets</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
61 public int ResendLimit; 60 public bool AdaptiveThrottlesEnabled;
62 /// <summary>Maximum burst rate for land packets</summary> 61
63 public int LandLimit;
64 /// <summary>Maximum burst rate for wind packets</summary>
65 public int WindLimit;
66 /// <summary>Maximum burst rate for cloud packets</summary>
67 public int CloudLimit;
68 /// <summary>Maximum burst rate for task (state and transaction) packets</summary>
69 public int TaskLimit;
70 /// <summary>Maximum burst rate for texture packets</summary>
71 public int TextureLimit;
72 /// <summary>Maximum burst rate for asset packets</summary>
73 public int AssetLimit;
74 /// <summary>Maximum burst rate for state packets</summary>
75 public int StateLimit;
76 /// <summary>Burst rate for the parent token bucket</summary>
77 public int TotalLimit;
78
79 /// <summary> 62 /// <summary>
80 /// Default constructor 63 /// Default constructor
81 /// </summary> 64 /// </summary>
@@ -86,26 +69,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
86 { 69 {
87 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; 70 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
88 71
89 Resend = throttleConfig.GetInt("resend_default", 12500); 72 Resend = throttleConfig.GetInt("resend_default", 6625);
90 Land = throttleConfig.GetInt("land_default", 1000); 73 Land = throttleConfig.GetInt("land_default", 9125);
91 Wind = throttleConfig.GetInt("wind_default", 1000); 74 Wind = throttleConfig.GetInt("wind_default", 1750);
92 Cloud = throttleConfig.GetInt("cloud_default", 1000); 75 Cloud = throttleConfig.GetInt("cloud_default", 1750);
93 Task = throttleConfig.GetInt("task_default", 1000); 76 Task = throttleConfig.GetInt("task_default", 18500);
94 Texture = throttleConfig.GetInt("texture_default", 1000); 77 Texture = throttleConfig.GetInt("texture_default", 18500);
95 Asset = throttleConfig.GetInt("asset_default", 1000); 78 Asset = throttleConfig.GetInt("asset_default", 10500);
96 State = throttleConfig.GetInt("state_default", 1000);
97
98 ResendLimit = throttleConfig.GetInt("resend_limit", 18750);
99 LandLimit = throttleConfig.GetInt("land_limit", 29750);
100 WindLimit = throttleConfig.GetInt("wind_limit", 18750);
101 CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
102 TaskLimit = throttleConfig.GetInt("task_limit", 18750);
103 TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
104 AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
105 StateLimit = throttleConfig.GetInt("state_limit", 37000);
106 79
107 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 80 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
108 TotalLimit = Total; 81
82 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
109 } 83 }
110 catch (Exception) { } 84 catch (Exception) { }
111 } 85 }
@@ -128,34 +102,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 return Texture; 102 return Texture;
129 case ThrottleOutPacketType.Asset: 103 case ThrottleOutPacketType.Asset:
130 return Asset; 104 return Asset;
131 case ThrottleOutPacketType.State:
132 return State;
133 case ThrottleOutPacketType.Unknown:
134 default:
135 return 0;
136 }
137 }
138
139 public int GetLimit(ThrottleOutPacketType type)
140 {
141 switch (type)
142 {
143 case ThrottleOutPacketType.Resend:
144 return ResendLimit;
145 case ThrottleOutPacketType.Land:
146 return LandLimit;
147 case ThrottleOutPacketType.Wind:
148 return WindLimit;
149 case ThrottleOutPacketType.Cloud:
150 return CloudLimit;
151 case ThrottleOutPacketType.Task:
152 return TaskLimit;
153 case ThrottleOutPacketType.Texture:
154 return TextureLimit;
155 case ThrottleOutPacketType.Asset:
156 return AssetLimit;
157 case ThrottleOutPacketType.State:
158 return StateLimit;
159 case ThrottleOutPacketType.Unknown: 105 case ThrottleOutPacketType.Unknown:
160 default: 106 default:
161 return 0; 107 return 0;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index 07b0a1d..29fd1a4 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -29,6 +29,8 @@ using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using OpenSim.Framework;
33
32using log4net; 34using log4net;
33 35
34namespace OpenSim.Region.ClientStack.LindenUDP 36namespace OpenSim.Region.ClientStack.LindenUDP
@@ -48,31 +50,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
48 /// Number of ticks (ms) per quantum, drip rate and max burst 50 /// Number of ticks (ms) per quantum, drip rate and max burst
49 /// are defined over this interval. 51 /// are defined over this interval.
50 /// </summary> 52 /// </summary>
51 private const Int32 m_ticksPerQuantum = 1000; 53 protected const Int32 m_ticksPerQuantum = 1000;
52 54
53 /// <summary> 55 /// <summary>
54 /// This is the number of quantums worth of packets that can 56 /// This is the number of quantums worth of packets that can
55 /// be accommodated during a burst 57 /// be accommodated during a burst
56 /// </summary> 58 /// </summary>
57 private const Double m_quantumsPerBurst = 1.5; 59 protected const Double m_quantumsPerBurst = 1.5;
58 60
59 /// <summary> 61 /// <summary>
60 /// </summary> 62 /// </summary>
61 private const Int32 m_minimumDripRate = 1400; 63 protected const Int32 m_minimumDripRate = 1400;
62 64
63 /// <summary>Time of the last drip, in system ticks</summary> 65 /// <summary>Time of the last drip, in system ticks</summary>
64 private Int32 m_lastDrip; 66 protected Int32 m_lastDrip;
65 67
66 /// <summary> 68 /// <summary>
67 /// The number of bytes that can be sent at this moment. This is the 69 /// The number of bytes that can be sent at this moment. This is the
68 /// current number of tokens in the bucket 70 /// current number of tokens in the bucket
69 /// </summary> 71 /// </summary>
70 private Int64 m_tokenCount; 72 protected Int64 m_tokenCount;
71 73
72 /// <summary> 74 /// <summary>
73 /// Map of children buckets and their requested maximum burst rate 75 /// Map of children buckets and their requested maximum burst rate
74 /// </summary> 76 /// </summary>
75 private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); 77 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
76 78
77#region Properties 79#region Properties
78 80
@@ -81,7 +83,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// parent. The parent bucket will limit the aggregate bandwidth of all 83 /// parent. The parent bucket will limit the aggregate bandwidth of all
82 /// of its children buckets 84 /// of its children buckets
83 /// </summary> 85 /// </summary>
84 private TokenBucket m_parent; 86 protected TokenBucket m_parent;
85 public TokenBucket Parent 87 public TokenBucket Parent
86 { 88 {
87 get { return m_parent; } 89 get { return m_parent; }
@@ -93,7 +95,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
93 /// of tokens that can accumulate in the bucket at any one time. This 95 /// of tokens that can accumulate in the bucket at any one time. This
94 /// also sets the total request for leaf nodes 96 /// also sets the total request for leaf nodes
95 /// </summary> 97 /// </summary>
96 private Int64 m_burstRate; 98 protected Int64 m_burstRate;
97 public Int64 RequestedBurstRate 99 public Int64 RequestedBurstRate
98 { 100 {
99 get { return m_burstRate; } 101 get { return m_burstRate; }
@@ -118,8 +120,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
118 /// <remarks>Tokens are added to the bucket any time 120 /// <remarks>Tokens are added to the bucket any time
119 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 121 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
120 /// the system tick interval (typically around 15-22ms)</remarks> 122 /// the system tick interval (typically around 15-22ms)</remarks>
121 private Int64 m_dripRate; 123 protected Int64 m_dripRate;
122 public Int64 RequestedDripRate 124 public virtual Int64 RequestedDripRate
123 { 125 {
124 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } 126 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
125 set { 127 set {
@@ -131,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
131 } 133 }
132 } 134 }
133 135
134 public Int64 DripRate 136 public virtual Int64 DripRate
135 { 137 {
136 get { 138 get {
137 if (m_parent == null) 139 if (m_parent == null)
@@ -149,7 +151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 /// The current total of the requested maximum burst rates of 151 /// The current total of the requested maximum burst rates of
150 /// this bucket's children buckets. 152 /// this bucket's children buckets.
151 /// </summary> 153 /// </summary>
152 private Int64 m_totalDripRequest; 154 protected Int64 m_totalDripRequest;
153 public Int64 TotalDripRequest 155 public Int64 TotalDripRequest
154 { 156 {
155 get { return m_totalDripRequest; } 157 get { return m_totalDripRequest; }
@@ -177,7 +179,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
177 RequestedDripRate = dripRate; 179 RequestedDripRate = dripRate;
178 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers 180 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
179 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); 181 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
180 m_lastDrip = Environment.TickCount & Int32.MaxValue; 182 m_lastDrip = Util.EnvironmentTickCount();
181 } 183 }
182 184
183#endregion Constructor 185#endregion Constructor
@@ -189,7 +191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
189 /// hierarchy. However, if any of the parents is over-booked, then 191 /// hierarchy. However, if any of the parents is over-booked, then
190 /// the modifier will be less than 1. 192 /// the modifier will be less than 1.
191 /// </summary> 193 /// </summary>
192 private double DripRateModifier() 194 protected double DripRateModifier()
193 { 195 {
194 Int64 driprate = DripRate; 196 Int64 driprate = DripRate;
195 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 197 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
@@ -197,7 +199,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
197 199
198 /// <summary> 200 /// <summary>
199 /// </summary> 201 /// </summary>
200 private double BurstRateModifier() 202 protected double BurstRateModifier()
201 { 203 {
202 // for now... burst rate is always m_quantumsPerBurst (constant) 204 // for now... burst rate is always m_quantumsPerBurst (constant)
203 // larger than drip rate so the ratio of burst requests is the 205 // larger than drip rate so the ratio of burst requests is the
@@ -211,12 +213,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
211 /// </summary> 213 /// </summary>
212 public void RegisterRequest(TokenBucket child, Int64 request) 214 public void RegisterRequest(TokenBucket child, Int64 request)
213 { 215 {
214 m_children[child] = request; 216 lock (m_children)
215 // m_totalDripRequest = m_children.Values.Sum(); 217 {
218 m_children[child] = request;
219 // m_totalDripRequest = m_children.Values.Sum();
216 220
217 m_totalDripRequest = 0; 221 m_totalDripRequest = 0;
218 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 222 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
219 m_totalDripRequest += cref.Value; 223 m_totalDripRequest += cref.Value;
224 }
220 225
221 // Pass the new values up to the parent 226 // Pass the new values up to the parent
222 if (m_parent != null) 227 if (m_parent != null)
@@ -229,12 +234,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
229 /// </summary> 234 /// </summary>
230 public void UnregisterRequest(TokenBucket child) 235 public void UnregisterRequest(TokenBucket child)
231 { 236 {
232 m_children.Remove(child); 237 lock (m_children)
233 // m_totalDripRequest = m_children.Values.Sum(); 238 {
239 m_children.Remove(child);
240 // m_totalDripRequest = m_children.Values.Sum();
234 241
235 m_totalDripRequest = 0; 242 m_totalDripRequest = 0;
236 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 243 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
237 m_totalDripRequest += cref.Value; 244 m_totalDripRequest += cref.Value;
245 }
246
238 247
239 // Pass the new values up to the parent 248 // Pass the new values up to the parent
240 if (m_parent != null) 249 if (m_parent != null)
@@ -268,7 +277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
268 /// Deposit tokens into the bucket from a child bucket that did 277 /// Deposit tokens into the bucket from a child bucket that did
269 /// not use all of its available tokens 278 /// not use all of its available tokens
270 /// </summary> 279 /// </summary>
271 private void Deposit(Int64 count) 280 protected void Deposit(Int64 count)
272 { 281 {
273 m_tokenCount += count; 282 m_tokenCount += count;
274 283
@@ -285,7 +294,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 /// call to Drip 294 /// call to Drip
286 /// </summary> 295 /// </summary>
287 /// <returns>True if tokens were added to the bucket, otherwise false</returns> 296 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
288 private void Drip() 297 protected void Drip()
289 { 298 {
290 // This should never happen... means we are a leaf node and were created 299 // This should never happen... means we are a leaf node and were created
291 // with no drip rate... 300 // with no drip rate...
@@ -297,10 +306,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
297 306
298 // Determine the interval over which we are adding tokens, never add 307 // Determine the interval over which we are adding tokens, never add
299 // more than a single quantum of tokens 308 // more than a single quantum of tokens
300 Int32 now = Environment.TickCount & Int32.MaxValue; 309 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum);
301 Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); 310 m_lastDrip = Util.EnvironmentTickCount();
302
303 m_lastDrip = now;
304 311
305 // This can be 0 in the very unusual case that the timer wrapped 312 // This can be 0 in the very unusual case that the timer wrapped
306 // It can be 0 if we try add tokens at a sub-tick rate 313 // It can be 0 if we try add tokens at a sub-tick rate
@@ -310,4 +317,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP
310 Deposit(deltaMS * DripRate / m_ticksPerQuantum); 317 Deposit(deltaMS * DripRate / m_ticksPerQuantum);
311 } 318 }
312 } 319 }
320
321 public class AdaptiveTokenBucket : TokenBucket
322 {
323 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
324
325 /// <summary>
326 /// The minimum rate for flow control. Minimum drip rate is one
327 /// packet per second. Open the throttle to 15 packets per second
328 /// or about 160kbps.
329 /// </summary>
330 protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
331
332 // <summary>
333 // The maximum rate for flow control. Drip rate can never be
334 // greater than this.
335 // </summary>
336 protected Int64 m_maxDripRate = 0;
337 protected Int64 MaxDripRate
338 {
339 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
340 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
341 }
342
343 private bool m_enabled = false;
344
345 // <summary>
346 //
347 // </summary>
348 public virtual Int64 AdjustedDripRate
349 {
350 get { return m_dripRate; }
351 set {
352 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate);
353 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
354 if (m_parent != null)
355 m_parent.RegisterRequest(this,m_dripRate);
356 }
357 }
358
359 // <summary>
360 //
361 // </summary>
362 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate)
363 {
364 m_enabled = enabled;
365
366 if (m_enabled)
367 {
368 // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled");
369 MaxDripRate = maxDripRate;
370 AdjustedDripRate = m_minimumFlow;
371 }
372 }
373
374 // <summary>
375 //
376 // </summary>
377 public void ExpirePackets(Int32 count)
378 {
379 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
380 if (m_enabled)
381 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
382 }
383
384 // <summary>
385 //
386 // </summary>
387 public void AcknowledgePackets(Int32 count)
388 {
389 if (m_enabled)
390 AdjustedDripRate = AdjustedDripRate + count;
391 }
392 }
313} 393}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index d195110..793aefe 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -65,7 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
65 /// <summary>Holds packets that need to be added to the unacknowledged list</summary> 65 /// <summary>Holds packets that need to be added to the unacknowledged list</summary>
66 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>(); 66 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>();
67 /// <summary>Holds information about pending acknowledgements</summary> 67 /// <summary>Holds information about pending acknowledgements</summary>
68 private LocklessQueue<PendingAck> m_pendingRemoves = new LocklessQueue<PendingAck>(); 68 private LocklessQueue<PendingAck> m_pendingAcknowledgements = new LocklessQueue<PendingAck>();
69 /// <summary>Holds information about pending removals</summary>
70 private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>();
69 71
70 /// <summary> 72 /// <summary>
71 /// Add an unacked packet to the collection 73 /// Add an unacked packet to the collection
@@ -83,15 +85,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 85
84 /// <summary> 86 /// <summary>
85 /// Marks a packet as acknowledged 87 /// Marks a packet as acknowledged
88 /// This method is used when an acknowledgement is received from the network for a previously
89 /// sent packet. Effects of removal this way are to update unacked byte count, adjust RTT
90 /// and increase throttle to the coresponding client.
86 /// </summary> 91 /// </summary>
87 /// <param name="sequenceNumber">Sequence number of the packet to 92 /// <param name="sequenceNumber">Sequence number of the packet to
88 /// acknowledge</param> 93 /// acknowledge</param>
89 /// <param name="currentTime">Current value of Environment.TickCount</param> 94 /// <param name="currentTime">Current value of Environment.TickCount</param>
90 /// <remarks>This does not immediately acknowledge the packet, it only 95 /// <remarks>This does not immediately acknowledge the packet, it only
91 /// queues the ack so it can be handled in a thread-safe way later</remarks> 96 /// queues the ack so it can be handled in a thread-safe way later</remarks>
92 public void Remove(uint sequenceNumber, int currentTime, bool fromResend) 97 public void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
93 { 98 {
94 m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); 99 m_pendingAcknowledgements.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
100 }
101
102 /// <summary>
103 /// Marks a packet as no longer needing acknowledgement without a received acknowledgement.
104 /// This method is called when a packet expires and we no longer need an acknowledgement.
105 /// When some reliable packet types expire, they are handled in a way other than simply
106 /// resending them. The only effect of removal this way is to update unacked byte count.
107 /// </summary>
108 /// <param name="sequenceNumber">Sequence number of the packet to
109 /// acknowledge</param>
110 /// <remarks>The does not immediately remove the packet, it only queues the removal
111 /// so it can be handled in a thread safe way later</remarks>
112 public void Remove(uint sequenceNumber)
113 {
114 m_pendingRemoves.Enqueue(sequenceNumber);
95 } 115 }
96 116
97 /// <summary> 117 /// <summary>
@@ -130,6 +150,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
130 // is actually sent out again 150 // is actually sent out again
131 packet.TickCount = 0; 151 packet.TickCount = 0;
132 152
153 // As with other network applications, assume that an expired packet is
154 // an indication of some network problem, slow transmission
155 packet.Client.FlowThrottle.ExpirePackets(1);
156
133 expiredPackets.Add(packet); 157 expiredPackets.Add(packet);
134 } 158 }
135 } 159 }
@@ -147,29 +171,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
147 m_packets[pendingAdd.SequenceNumber] = pendingAdd; 171 m_packets[pendingAdd.SequenceNumber] = pendingAdd;
148 172
149 // Process all the pending removes, including updating statistics and round-trip times 173 // Process all the pending removes, including updating statistics and round-trip times
150 PendingAck pendingRemove; 174 PendingAck pendingAcknowledgement;
151 OutgoingPacket ackedPacket; 175 while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement))
152 while (m_pendingRemoves.TryDequeue(out pendingRemove))
153 { 176 {
154 if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket)) 177 OutgoingPacket ackedPacket;
178 if (m_packets.TryGetValue(pendingAcknowledgement.SequenceNumber, out ackedPacket))
155 { 179 {
156 if (ackedPacket != null) 180 if (ackedPacket != null)
157 { 181 {
158 m_packets.Remove(pendingRemove.SequenceNumber); 182 m_packets.Remove(pendingAcknowledgement.SequenceNumber);
183
184 // As with other network applications, assume that an acknowledged packet is an
185 // indication that the network can handle a little more load, speed up the transmission
186 ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength);
159 187
160 // Update stats 188 // Update stats
161 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); 189 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
162 190
163 if (!pendingRemove.FromResend) 191 if (!pendingAcknowledgement.FromResend)
164 { 192 {
165 // Calculate the round-trip time for this packet and its ACK 193 // Calculate the round-trip time for this packet and its ACK
166 int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount; 194 int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount;
167 if (rtt > 0) 195 if (rtt > 0)
168 ackedPacket.Client.UpdateRoundTrip(rtt); 196 ackedPacket.Client.UpdateRoundTrip(rtt);
169 } 197 }
170 } 198 }
171 } 199 }
172 } 200 }
201
202 uint pendingRemove;
203 while(m_pendingRemoves.TryDequeue(out pendingRemove))
204 {
205 OutgoingPacket removedPacket;
206 if (m_packets.TryGetValue(pendingRemove, out removedPacket))
207 {
208 if (removedPacket != null)
209 {
210 m_packets.Remove(pendingRemove);
211
212 // Update stats
213 Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength);
214 }
215 }
216 }
173 } 217 }
174 } 218 }
175} \ No newline at end of file 219}
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
index 771038e..9d8082b 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
@@ -41,8 +41,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
41 /// </summary> 41 /// </summary>
42 public class AgentAssetTransactions 42 public class AgentAssetTransactions
43 { 43 {
44// private static readonly ILog m_log = LogManager.GetLogger( 44// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45// MethodBase.GetCurrentMethod().DeclaringType);
46 45
47 // Fields 46 // Fields
48 private bool m_dumpAssetsToFile; 47 private bool m_dumpAssetsToFile;
@@ -149,6 +148,10 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
149 148
150 if (asset != null) 149 if (asset != null)
151 { 150 {
151// m_log.DebugFormat(
152// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}",
153// item.Name, part.Name, transactionID);
154
152 asset.FullID = UUID.Random(); 155 asset.FullID = UUID.Random();
153 asset.Name = item.Name; 156 asset.Name = item.Name;
154 asset.Description = item.Description; 157 asset.Description = item.Description;
@@ -156,8 +159,6 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
156 item.AssetID = asset.FullID; 159 item.AssetID = asset.FullID;
157 160
158 m_Scene.AssetService.Store(asset); 161 m_Scene.AssetService.Store(asset);
159
160 part.Inventory.UpdateInventoryItem(item);
161 } 162 }
162 } 163 }
163 } 164 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index ff26264..520d794 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -562,14 +562,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
562 /// <param name="sp"></param> 562 /// <param name="sp"></param>
563 /// <param name="so"></param> 563 /// <param name="so"></param>
564 /// <param name="attachmentpoint"></param> 564 /// <param name="attachmentpoint"></param>
565 /// <param name="AttachOffset"></param> 565 /// <param name="attachOffset"></param>
566 /// <param name="silent"></param> 566 /// <param name="silent"></param>
567 protected void AttachToAgent(ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 AttachOffset, bool silent) 567 protected void AttachToAgent(ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
568 { 568 {
569 // don't attach attachments to child agents
570 if (avatar.IsChildAgent) return;
571 569
572// m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1}", Name, avatar.Name); 570 m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", Name, avatar.Name,
571 attachmentpoint, attachOffset, so.RootPart.AttachedPos);
573 572
574 so.DetachFromBackup(); 573 so.DetachFromBackup();
575 574
@@ -590,8 +589,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
590 so.RootPart.PhysActor = null; 589 so.RootPart.PhysActor = null;
591 } 590 }
592 591
593 so.AbsolutePosition = AttachOffset; 592 so.AbsolutePosition = attachOffset;
594 so.RootPart.AttachedPos = AttachOffset; 593 so.RootPart.AttachedPos = attachOffset;
595 so.RootPart.IsAttachment = true; 594 so.RootPart.IsAttachment = true;
596 595
597 so.RootPart.SetParentLocalId(avatar.LocalId); 596 so.RootPart.SetParentLocalId(avatar.LocalId);
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index c88be7d..b985fbb 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -285,11 +285,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
285 } 285 }
286 286
287 string reason; 287 string reason;
288 if (!m_aScene.SimulationService.QueryAccess(finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out reason)) 288 string version;
289 if (!m_aScene.SimulationService.QueryAccess(finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason))
289 { 290 {
290 sp.ControllingClient.SendTeleportFailed("Teleport failed: " + reason); 291 sp.ControllingClient.SendTeleportFailed("Teleport failed: " + reason);
291 return; 292 return;
292 } 293 }
294 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version);
293 295
294 sp.ControllingClient.SendTeleportStart(teleportFlags); 296 sp.ControllingClient.SendTeleportStart(teleportFlags);
295 297
@@ -371,20 +373,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
371 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); 373 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
372 } 374 }
373 375
374 // Expect avatar crossing is a heavy-duty function at the destination.
375 // That is where MakeRoot is called, which fetches appearance and inventory.
376 // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates.
377 //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
378 // position, false);
379
380 //{
381 // avatar.ControllingClient.SendTeleportFailed("Problem with destination.");
382 // // We should close that agent we just created over at destination...
383 // List<ulong> lst = new List<ulong>();
384 // lst.Add(reg.RegionHandle);
385 // SendCloseChildAgentAsync(avatar.UUID, lst);
386 // return;
387 //}
388 376
389 SetInTransit(sp.UUID); 377 SetInTransit(sp.UUID);
390 378
@@ -426,7 +414,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
426 414
427 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 415 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
428 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 416 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
429 // that the client contacted the destination before we send the attachments and close things here. 417 // that the client contacted the destination before we close things here.
430 if (!WaitForCallback(sp.UUID)) 418 if (!WaitForCallback(sp.UUID))
431 { 419 {
432 m_log.WarnFormat( 420 m_log.WarnFormat(
@@ -437,14 +425,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
437 return; 425 return;
438 } 426 }
439 427
440 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it 428 // For backwards compatibility
441 CrossAttachmentsIntoNewRegion(finalDestination, sp, true); 429 if (version == "Unknown" || version == string.Empty)
430 {
431 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
432 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one...");
433 CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
434 }
435
436 // May need to logout or other cleanup
437 AgentHasMovedAway(sp, logout);
442 438
443 // Well, this is it. The agent is over there. 439 // Well, this is it. The agent is over there.
444 KillEntity(sp.Scene, sp.LocalId); 440 KillEntity(sp.Scene, sp.LocalId);
445 441
446 // May need to logout or other cleanup
447 AgentHasMovedAway(sp.ControllingClient.SessionId, logout);
448 442
449 // Now let's make it officially a child agent 443 // Now let's make it officially a child agent
450 sp.MakeChildAgent(); 444 sp.MakeChildAgent();
@@ -485,7 +479,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
485 479
486 // Fail. Reset it back 480 // Fail. Reset it back
487 sp.IsChildAgent = false; 481 sp.IsChildAgent = false;
488 482 ReInstantiateScripts(sp);
489 ResetFromTransit(sp.UUID); 483 ResetFromTransit(sp.UUID);
490 484
491 EnableChildAgents(sp); 485 EnableChildAgents(sp);
@@ -513,8 +507,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
513 507
514 } 508 }
515 509
516 protected virtual void AgentHasMovedAway(UUID sessionID, bool logout) 510 protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout)
517 { 511 {
512 foreach (SceneObjectGroup sop in sp.Attachments)
513 {
514 sop.Scene.DeleteSceneObject(sop, true);
515 }
516 sp.Attachments.Clear();
518 } 517 }
519 518
520 protected void KillEntity(Scene scene, uint localID) 519 protected void KillEntity(Scene scene, uint localID)
@@ -784,7 +783,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
784 GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); 783 GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
785 784
786 string reason; 785 string reason;
787 if (!scene.SimulationService.QueryAccess(neighbourRegion, agent.ControllingClient.AgentId, newpos, out reason)) 786 string version;
787 if (!scene.SimulationService.QueryAccess(neighbourRegion, agent.ControllingClient.AgentId, newpos, out version, out reason))
788 { 788 {
789 agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel"); 789 agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel");
790 if (r == null) 790 if (r == null)
@@ -804,7 +804,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
804 agent.InTransit(); 804 agent.InTransit();
805 805
806 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; 806 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync;
807 d.BeginInvoke(agent, newpos, neighbourx, neighboury, neighbourRegion, isFlying, CrossAgentToNewRegionCompleted, d); 807 d.BeginInvoke(agent, newpos, neighbourx, neighboury, neighbourRegion, isFlying, version, CrossAgentToNewRegionCompleted, d);
808 808
809 return true; 809 return true;
810 } 810 }
@@ -861,17 +861,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
861 icon.EndInvoke(iar); 861 icon.EndInvoke(iar);
862 } 862 }
863 863
864 public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying); 864 public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying, string version);
865 865
866 /// <summary> 866 /// <summary>
867 /// This Closes child agents on neighbouring regions 867 /// This Closes child agents on neighbouring regions
868 /// Calls an asynchronous method to do so.. so it doesn't lag the sim. 868 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
869 /// </summary> 869 /// </summary>
870 protected ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying) 870 protected ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying, string version)
871 { 871 {
872 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); 872 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
873 873
874 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3}", agent.Firstname, agent.Lastname, neighbourx, neighboury); 874 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3} running version {4}", agent.Firstname, agent.Lastname, neighbourx, neighboury, version);
875 875
876 Scene m_scene = agent.Scene; 876 Scene m_scene = agent.Scene;
877 877
@@ -930,6 +930,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
930 if (!WaitForCallback(agent.UUID)) 930 if (!WaitForCallback(agent.UUID))
931 { 931 {
932 m_log.Debug("[ENTITY TRANSFER MODULE]: Callback never came in crossing agent"); 932 m_log.Debug("[ENTITY TRANSFER MODULE]: Callback never came in crossing agent");
933 ReInstantiateScripts(agent);
933 ResetFromTransit(agent.UUID); 934 ResetFromTransit(agent.UUID);
934 935
935 // Yikes! We should just have a ref to scene here. 936 // Yikes! We should just have a ref to scene here.
@@ -945,7 +946,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
945 agent.SendOtherAgentsAvatarDataToMe(); 946 agent.SendOtherAgentsAvatarDataToMe();
946 agent.SendOtherAgentsAppearanceToMe(); 947 agent.SendOtherAgentsAppearanceToMe();
947 948
948 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true); 949 // Backwards compatibility
950 if (version == "Unknown" || version == string.Empty)
951 {
952 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old neighbor, passing attachments one by one...");
953 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
954 }
955
956 AgentHasMovedAway(agent, false);
949 957
950 // the user may change their profile information in other region, 958 // the user may change their profile information in other region,
951 // so the userinfo in UserProfileCache is not reliable any more, delete it 959 // so the userinfo in UserProfileCache is not reliable any more, delete it
@@ -1749,7 +1757,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1749 return false; 1757 return false;
1750 } 1758 }
1751 1759
1752 1760 protected void ReInstantiateScripts(ScenePresence sp)
1761 {
1762 sp.Attachments.ForEach(delegate(SceneObjectGroup sog)
1763 {
1764 sog.CreateScriptInstances(0, false, sp.Scene.DefaultScriptEngine, 0);
1765 sog.ResumeScripts();
1766 });
1767 }
1753 #endregion 1768 #endregion
1754 1769
1755 } 1770 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 79e76b4..5c53f78 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -142,11 +142,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
142 return false; 142 return false;
143 } 143 }
144 144
145 protected override void AgentHasMovedAway(UUID sessionID, bool logout) 145 protected override void AgentHasMovedAway(ScenePresence sp, bool logout)
146 { 146 {
147 base.AgentHasMovedAway(sp, logout);
147 if (logout) 148 if (logout)
148 // Log them out of this grid 149 // Log them out of this grid
149 m_aScene.PresenceService.LogoutAgent(sessionID); 150 m_aScene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
150 } 151 }
151 152
152 protected override bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) 153 protected override bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index a298b65..2cf02b5 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -41,6 +41,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
41 public class LocalSimulationConnectorModule : ISharedRegionModule, ISimulationService 41 public class LocalSimulationConnectorModule : ISharedRegionModule, ISimulationService
42 { 42 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 // Version of this service
45 private const string m_Version = "SIMULATION/0.1";
46
44 private List<Scene> m_sceneList = new List<Scene>(); 47 private List<Scene> m_sceneList = new List<Scene>();
45 48
46 private IEntityTransferModule m_AgentTransferModule; 49 private IEntityTransferModule m_AgentTransferModule;
@@ -257,9 +260,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
257 return false; 260 return false;
258 } 261 }
259 262
260 public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string reason) 263 public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason)
261 { 264 {
262 reason = "Communications failure"; 265 reason = "Communications failure";
266 version = m_Version;
263 if (destination == null) 267 if (destination == null)
264 return false; 268 return false;
265 269
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
index 67f4d60..f8cea71 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
@@ -179,7 +179,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
179 return true; 179 return true;
180 180
181 // else do the remote thing 181 // else do the remote thing
182 if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) 182 if (!m_localBackend.IsLocalRegion(destination.RegionID))
183 { 183 {
184 return m_remoteConnector.CreateAgent(destination, aCircuit, teleportFlags, out reason); 184 return m_remoteConnector.CreateAgent(destination, aCircuit, teleportFlags, out reason);
185 } 185 }
@@ -229,19 +229,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
229 229
230 } 230 }
231 231
232 public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string reason) 232 public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason)
233 { 233 {
234 reason = "Communications failure"; 234 reason = "Communications failure";
235 version = "Unknown";
235 if (destination == null) 236 if (destination == null)
236 return false; 237 return false;
237 238
238 // Try local first 239 // Try local first
239 if (m_localBackend.QueryAccess(destination, id, position, out reason)) 240 if (m_localBackend.QueryAccess(destination, id, position, out version, out reason))
240 return true; 241 return true;
241 242
242 // else do the remote thing 243 // else do the remote thing
243 if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) 244 if (!m_localBackend.IsLocalRegion(destination.RegionID))
244 return m_remoteConnector.QueryAccess(destination, id, position, out reason); 245 return m_remoteConnector.QueryAccess(destination, id, position, out version, out reason);
245 246
246 return false; 247 return false;
247 248
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index e3ed905..4595a29 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -119,16 +119,40 @@ namespace OpenSim.Region.Framework.Scenes
119 119
120 private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) 120 private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
121 { 121 {
122 return 1; 122 // And anything attached to this avatar gets top priority as well
123 if (entity is SceneObjectPart)
124 {
125 SceneObjectPart sop = (SceneObjectPart)entity;
126 if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
127 return 1;
128 }
129
130 return PriorityQueue.NumberOfImmediateQueues; // first queue past the immediate queues
123 } 131 }
124 132
125 private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) 133 private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
126 { 134 {
135 // And anything attached to this avatar gets top priority as well
136 if (entity is SceneObjectPart)
137 {
138 SceneObjectPart sop = (SceneObjectPart)entity;
139 if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
140 return 1;
141 }
142
127 return ComputeDistancePriority(client,entity,false); 143 return ComputeDistancePriority(client,entity,false);
128 } 144 }
129 145
130 private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) 146 private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
131 { 147 {
148 // And anything attached to this avatar gets top priority as well
149 if (entity is SceneObjectPart)
150 {
151 SceneObjectPart sop = (SceneObjectPart)entity;
152 if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
153 return 1;
154 }
155
132 return ComputeDistancePriority(client,entity,true); 156 return ComputeDistancePriority(client,entity,true);
133 } 157 }
134 158
@@ -141,18 +165,20 @@ namespace OpenSim.Region.Framework.Scenes
141 { 165 {
142 if (!presence.IsChildAgent) 166 if (!presence.IsChildAgent)
143 { 167 {
168 // All avatars other than our own go into pqueue 1
169 if (entity is ScenePresence)
170 return 1;
171
144 if (entity is SceneObjectPart) 172 if (entity is SceneObjectPart)
145 { 173 {
174 // Attachments are high priority,
175 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
176 return 1;
177
146 // Non physical prims are lower priority than physical prims 178 // Non physical prims are lower priority than physical prims
147 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; 179 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
148 if (physActor == null || !physActor.IsPhysical) 180 if (physActor == null || !physActor.IsPhysical)
149 pqueue++; 181 pqueue++;
150
151 // Attachments are high priority,
152 // MIC: shouldn't these already be in the highest priority queue already
153 // since their root position is same as the avatars?
154 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
155 pqueue = 1;
156 } 182 }
157 } 183 }
158 } 184 }
@@ -172,7 +198,7 @@ namespace OpenSim.Region.Framework.Scenes
172 198
173 // m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); 199 // m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId);
174 // throw new InvalidOperationException("Prioritization agent not defined"); 200 // throw new InvalidOperationException("Prioritization agent not defined");
175 return Int32.MaxValue; 201 return PriorityQueue.NumberOfQueues - 1;
176 } 202 }
177 203
178 // Use group position for child prims, since we are putting child prims in 204 // Use group position for child prims, since we are putting child prims in
@@ -197,8 +223,10 @@ namespace OpenSim.Region.Framework.Scenes
197 223
198 // And convert the distance to a priority queue, this computation gives queues 224 // And convert the distance to a priority queue, this computation gives queues
199 // at 10, 20, 40, 80, 160, 320, 640, and 1280m 225 // at 10, 20, 40, 80, 160, 320, 640, and 1280m
200 uint pqueue = 1; 226 uint pqueue = PriorityQueue.NumberOfImmediateQueues;
201 for (int i = 0; i < 8; i++) 227 uint queues = PriorityQueue.NumberOfQueues - PriorityQueue.NumberOfImmediateQueues;
228
229 for (int i = 0; i < queues - 1; i++)
202 { 230 {
203 if (distance < 10 * Math.Pow(2.0,i)) 231 if (distance < 10 * Math.Pow(2.0,i))
204 break; 232 break;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 0f85925..b0f0de6 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -1430,6 +1430,10 @@ namespace OpenSim.Region.Framework.Scenes
1430 } 1430 }
1431 else // Updating existing item with new perms etc 1431 else // Updating existing item with new perms etc
1432 { 1432 {
1433// m_log.DebugFormat(
1434// "[PRIM INVENTORY]: Updating item {0} in {1} for UpdateTaskInventory()",
1435// currentItem.Name, part.Name);
1436
1433 IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>(); 1437 IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
1434 if (agentTransactions != null) 1438 if (agentTransactions != null)
1435 { 1439 {
@@ -2039,6 +2043,12 @@ namespace OpenSim.Region.Framework.Scenes
2039 if (rot != null) 2043 if (rot != null)
2040 group.UpdateGroupRotationR((Quaternion)rot); 2044 group.UpdateGroupRotationR((Quaternion)rot);
2041 2045
2046 // TODO: This needs to be refactored with the similar code in
2047 // SceneGraph.AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, Vector3 pos, Quaternion rot, Vector3 vel)
2048 // possibly by allowing this method to take a null rotation.
2049 if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical && vel != Vector3.Zero)
2050 group.RootPart.ApplyImpulse((vel * group.GetMass()), false);
2051
2042 // We can only call this after adding the scene object, since the scene object references the scene 2052 // We can only call this after adding the scene object, since the scene object references the scene
2043 // to find out if scripts should be activated at all. 2053 // to find out if scripts should be activated at all.
2044 group.CreateScriptInstances(param, true, DefaultScriptEngine, 3); 2054 group.CreateScriptInstances(param, true, DefaultScriptEngine, 3);
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 01de824..7c5e246 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1229,7 +1229,6 @@ namespace OpenSim.Region.Framework.Scenes
1229 1229
1230 // Increment the frame counter 1230 // Increment the frame counter
1231 ++Frame; 1231 ++Frame;
1232
1233 try 1232 try
1234 { 1233 {
1235 // Check if any objects have reached their targets 1234 // Check if any objects have reached their targets
@@ -2316,7 +2315,9 @@ namespace OpenSim.Region.Framework.Scenes
2316 /// <returns></returns> 2315 /// <returns></returns>
2317 public bool IncomingCreateObject(ISceneObject sog) 2316 public bool IncomingCreateObject(ISceneObject sog)
2318 { 2317 {
2319 //m_log.Debug(" >>> IncomingCreateObject(sog) <<< " + ((SceneObjectGroup)sog).AbsolutePosition + " deleted? " + ((SceneObjectGroup)sog).IsDeleted); 2318 //m_log.DebugFormat(" >>> IncomingCreateObject(sog) <<< {0} deleted? {1} isAttach? {2}", ((SceneObjectGroup)sog).AbsolutePosition,
2319 // ((SceneObjectGroup)sog).IsDeleted, ((SceneObjectGroup)sog).RootPart.IsAttachment);
2320
2320 SceneObjectGroup newObject; 2321 SceneObjectGroup newObject;
2321 try 2322 try
2322 { 2323 {
@@ -2334,9 +2335,29 @@ namespace OpenSim.Region.Framework.Scenes
2334 return false; 2335 return false;
2335 } 2336 }
2336 2337
2337 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); 2338 // For attachments, we need to wait until the agent is root
2338 2339 // before we restart the scripts, or else some functions won't work.
2339 newObject.ResumeScripts(); 2340 if (!newObject.IsAttachment)
2341 {
2342 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject));
2343 newObject.ResumeScripts();
2344 }
2345 else
2346 {
2347 ScenePresence sp;
2348 if (TryGetScenePresence(newObject.OwnerID, out sp))
2349 {
2350 // If the scene presence is here and already a root
2351 // agent, we came from a ;egacy region. Start the scripts
2352 // here as they used to start.
2353 // TODO: Remove in 0.7.3
2354 if (!sp.IsChildAgent)
2355 {
2356 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject));
2357 newObject.ResumeScripts();
2358 }
2359 }
2360 }
2340 2361
2341 // Do this as late as possible so that listeners have full access to the incoming object 2362 // Do this as late as possible so that listeners have full access to the incoming object
2342 EventManager.TriggerOnIncomingSceneObject(newObject); 2363 EventManager.TriggerOnIncomingSceneObject(newObject);
@@ -2453,17 +2474,8 @@ namespace OpenSim.Region.Framework.Scenes
2453 ScenePresence sp = GetScenePresence(sog.OwnerID); 2474 ScenePresence sp = GetScenePresence(sog.OwnerID);
2454 2475
2455 if (sp != null) 2476 if (sp != null)
2456 { 2477 return sp.GetStateSource();
2457 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(sp.UUID);
2458 2478
2459 if (aCircuit != null && (aCircuit.teleportFlags != (uint)TeleportFlags.Default))
2460 {
2461 // This will get your attention
2462 //m_log.Error("[XXX] Triggering CHANGED_TELEPORT");
2463
2464 return 5; // StateSource.Teleporting
2465 }
2466 }
2467 return 2; // StateSource.PrimCrossing 2479 return 2; // StateSource.PrimCrossing
2468 } 2480 }
2469 2481
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index 3281eab..3b60f8c 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -693,8 +693,9 @@ namespace OpenSim.Region.Framework.Scenes
693 { 693 {
694 TaskInventoryItem it = GetInventoryItem(item.ItemID); 694 TaskInventoryItem it = GetInventoryItem(item.ItemID);
695 if (it != null) 695 if (it != null)
696
697 { 696 {
697// m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
698
698 item.ParentID = m_part.UUID; 699 item.ParentID = m_part.UUID;
699 item.ParentPartID = m_part.UUID; 700 item.ParentPartID = m_part.UUID;
700 701
@@ -711,14 +712,16 @@ namespace OpenSim.Region.Framework.Scenes
711 m_items[item.ItemID] = item; 712 m_items[item.ItemID] = item;
712 m_inventorySerial++; 713 m_inventorySerial++;
713 } 714 }
714 715
715 if (fireScriptEvents) 716 if (fireScriptEvents)
716 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 717 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
718
717 if (considerChanged) 719 if (considerChanged)
718 { 720 {
719 HasInventoryChanged = true; 721 HasInventoryChanged = true;
720 m_part.ParentGroup.HasGroupChanged = true; 722 m_part.ParentGroup.HasGroupChanged = true;
721 } 723 }
724
722 return true; 725 return true;
723 } 726 }
724 else 727 else
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 00a1487..5b86735 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -840,6 +840,9 @@ namespace OpenSim.Region.Framework.Scenes
840 840
841 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); 841 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
842 842
843 bool wasChild = m_isChildAgent;
844 m_isChildAgent = false;
845
843 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 846 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
844 if (gm != null) 847 if (gm != null)
845 m_grouptitle = gm.GetGroupTitle(m_uuid); 848 m_grouptitle = gm.GetGroupTitle(m_uuid);
@@ -929,14 +932,21 @@ namespace OpenSim.Region.Framework.Scenes
929 // Animator.SendAnimPack(); 932 // Animator.SendAnimPack();
930 933
931 m_scene.SwapRootAgentCount(false); 934 m_scene.SwapRootAgentCount(false);
932 935
933 //CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(m_uuid); 936 // The initial login scene presence is already root when it gets here
934 //if (userInfo != null) 937 // and it has already rezzed the attachments and started their scripts.
935 // userInfo.FetchInventory(); 938 // We do the following only for non-login agents, because their scripts
936 //else 939 // haven't started yet.
937 // m_log.ErrorFormat("[SCENE]: Could not find user info for {0} when making it a root agent", m_uuid); 940 if (wasChild && Attachments != null && Attachments.Count > 0)
938 941 {
939 m_isChildAgent = false; 942 m_log.DebugFormat("[SCENE PRESENCE]: Restarting scripts in attachments...");
943 // Resume scripts
944 Attachments.ForEach(delegate(SceneObjectGroup sog)
945 {
946 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
947 sog.ResumeScripts();
948 });
949 }
940 950
941 // send the animations of the other presences to me 951 // send the animations of the other presences to me
942 m_scene.ForEachScenePresence(delegate(ScenePresence presence) 952 m_scene.ForEachScenePresence(delegate(ScenePresence presence)
@@ -948,6 +958,20 @@ namespace OpenSim.Region.Framework.Scenes
948 m_scene.EventManager.TriggerOnMakeRootAgent(this); 958 m_scene.EventManager.TriggerOnMakeRootAgent(this);
949 } 959 }
950 960
961 public int GetStateSource()
962 {
963 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(UUID);
964
965 if (aCircuit != null && (aCircuit.teleportFlags != (uint)TeleportFlags.Default))
966 {
967 // This will get your attention
968 //m_log.Error("[XXX] Triggering CHANGED_TELEPORT");
969
970 return 5; // StateSource.Teleporting
971 }
972 return 2; // StateSource.PrimCrossing
973 }
974
951 /// <summary> 975 /// <summary>
952 /// This turns a root agent into a child agent 976 /// This turns a root agent into a child agent
953 /// when an agent departs this region for a neighbor, this gets called. 977 /// when an agent departs this region for a neighbor, this gets called.
@@ -1139,7 +1163,6 @@ namespace OpenSim.Region.Framework.Scenes
1139 AbsolutePosition = pos; 1163 AbsolutePosition = pos;
1140 } 1164 }
1141 1165
1142 m_isChildAgent = false;
1143 bool m_flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); 1166 bool m_flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
1144 MakeRootAgent(AbsolutePosition, m_flying); 1167 MakeRootAgent(AbsolutePosition, m_flying);
1145 1168
@@ -2340,12 +2363,14 @@ namespace OpenSim.Region.Framework.Scenes
2340 2363
2341 #region Update Client(s) 2364 #region Update Client(s)
2342 2365
2366
2343 /// <summary> 2367 /// <summary>
2344 /// Sends a location update to the client connected to this scenePresence 2368 /// Sends a location update to the client connected to this scenePresence
2345 /// </summary> 2369 /// </summary>
2346 /// <param name="remoteClient"></param> 2370 /// <param name="remoteClient"></param>
2347 public void SendTerseUpdateToClient(IClientAPI remoteClient) 2371 public void SendTerseUpdateToClient(IClientAPI remoteClient)
2348 { 2372 {
2373
2349 // If the client is inactive, it's getting its updates from another 2374 // If the client is inactive, it's getting its updates from another
2350 // server. 2375 // server.
2351 if (remoteClient.IsActive) 2376 if (remoteClient.IsActive)
@@ -2358,8 +2383,8 @@ namespace OpenSim.Region.Framework.Scenes
2358 //m_log.DebugFormat("[SCENEPRESENCE]: TerseUpdate: Pos={0} Rot={1} Vel={2}", m_pos, m_bodyRot, m_velocity); 2383 //m_log.DebugFormat("[SCENEPRESENCE]: TerseUpdate: Pos={0} Rot={1} Vel={2}", m_pos, m_bodyRot, m_velocity);
2359 2384
2360 remoteClient.SendPrimUpdate( 2385 remoteClient.SendPrimUpdate(
2361 this, 2386 this,
2362 PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity 2387 PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity
2363 | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity); 2388 | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity);
2364 2389
2365 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 2390 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
@@ -2367,16 +2392,31 @@ namespace OpenSim.Region.Framework.Scenes
2367 } 2392 }
2368 } 2393 }
2369 2394
2395
2396 // vars to support reduced update frequency when velocity is unchanged
2397 private Vector3 lastVelocitySentToAllClients = Vector3.Zero;
2398 private int lastTerseUpdateToAllClientsTick = Util.EnvironmentTickCount();
2399
2370 /// <summary> 2400 /// <summary>
2371 /// Send a location/velocity/accelleration update to all agents in scene 2401 /// Send a location/velocity/accelleration update to all agents in scene
2372 /// </summary> 2402 /// </summary>
2373 public void SendTerseUpdateToAllClients() 2403 public void SendTerseUpdateToAllClients()
2374 { 2404 {
2375 m_perfMonMS = Util.EnvironmentTickCount(); 2405 int currentTick = Util.EnvironmentTickCount();
2376
2377 m_scene.ForEachClient(SendTerseUpdateToClient);
2378 2406
2379 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 2407 // decrease update frequency when avatar is moving but velocity is not changing
2408 if (m_velocity.Length() < 0.01f
2409 || Vector3.Distance(lastVelocitySentToAllClients, m_velocity) > 0.01f
2410 || currentTick - lastTerseUpdateToAllClientsTick > 1500)
2411 {
2412 m_perfMonMS = currentTick;
2413 lastVelocitySentToAllClients = m_velocity;
2414 lastTerseUpdateToAllClientsTick = currentTick;
2415
2416 m_scene.ForEachClient(SendTerseUpdateToClient);
2417
2418 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
2419 }
2380 } 2420 }
2381 2421
2382 public void SendCoarseLocations(List<Vector3> coarseLocations, List<UUID> avatarUUIDs) 2422 public void SendCoarseLocations(List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
@@ -2632,18 +2672,17 @@ namespace OpenSim.Region.Framework.Scenes
2632 cadu.GroupAccess = 0; 2672 cadu.GroupAccess = 0;
2633 cadu.Position = AbsolutePosition; 2673 cadu.Position = AbsolutePosition;
2634 cadu.regionHandle = m_rootRegionHandle; 2674 cadu.regionHandle = m_rootRegionHandle;
2675
2676 // Throttles
2635 float multiplier = 1; 2677 float multiplier = 1;
2636 int innacurateNeighbors = m_scene.GetInaccurateNeighborCount(); 2678 int childRegions = m_knownChildRegions.Count;
2637 if (innacurateNeighbors != 0) 2679 if (childRegions != 0)
2638 { 2680 multiplier = 1f / childRegions;
2639 multiplier = 1f / (float)innacurateNeighbors; 2681
2640 } 2682 // Minimum throttle for a child region is 1/4 of the root region throttle
2641 if (multiplier <= 0f) 2683 if (multiplier <= 0.25f)
2642 {
2643 multiplier = 0.25f; 2684 multiplier = 0.25f;
2644 }
2645 2685
2646 //m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
2647 cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier); 2686 cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier);
2648 cadu.Velocity = Velocity; 2687 cadu.Velocity = Velocity;
2649 2688
@@ -3039,16 +3078,14 @@ namespace OpenSim.Region.Framework.Scenes
3039 3078
3040 // Throttles 3079 // Throttles
3041 float multiplier = 1; 3080 float multiplier = 1;
3042 int innacurateNeighbors = m_scene.GetInaccurateNeighborCount(); 3081 int childRegions = m_knownChildRegions.Count;
3043 if (innacurateNeighbors != 0) 3082 if (childRegions != 0)
3044 { 3083 multiplier = 1f / childRegions;
3045 multiplier = 1f / innacurateNeighbors; 3084
3046 } 3085 // Minimum throttle for a child region is 1/4 of the root region throttle
3047 if (multiplier <= 0f) 3086 if (multiplier <= 0.25f)
3048 {
3049 multiplier = 0.25f; 3087 multiplier = 0.25f;
3050 } 3088
3051 //m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
3052 cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier); 3089 cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier);
3053 3090
3054 cAgent.HeadRotation = m_headrotation; 3091 cAgent.HeadRotation = m_headrotation;
@@ -3064,54 +3101,6 @@ namespace OpenSim.Region.Framework.Scenes
3064 3101
3065 cAgent.Appearance = new AvatarAppearance(m_appearance); 3102 cAgent.Appearance = new AvatarAppearance(m_appearance);
3066 3103
3067/*
3068 try
3069 {
3070 // We might not pass the Wearables in all cases...
3071 // They're only needed so that persistent changes to the appearance
3072 // are preserved in the new region where the user is moving to.
3073 // But in Hypergrid we might not let this happen.
3074 int i = 0;
3075 UUID[] wears = new UUID[m_appearance.Wearables.Length * 2];
3076 foreach (AvatarWearable aw in m_appearance.Wearables)
3077 {
3078 if (aw != null)
3079 {
3080 wears[i++] = aw.ItemID;
3081 wears[i++] = aw.AssetID;
3082 }
3083 else
3084 {
3085 wears[i++] = UUID.Zero;
3086 wears[i++] = UUID.Zero;
3087 }
3088 }
3089 cAgent.Wearables = wears;
3090
3091 cAgent.VisualParams = m_appearance.VisualParams;
3092
3093 if (m_appearance.Texture != null)
3094 cAgent.AgentTextures = m_appearance.Texture.GetBytes();
3095 }
3096 catch (Exception e)
3097 {
3098 m_log.Warn("[SCENE PRESENCE]: exception in CopyTo " + e.Message);
3099 }
3100
3101 //Attachments
3102 List<int> attPoints = m_appearance.GetAttachedPoints();
3103 if (attPoints != null)
3104 {
3105 //m_log.DebugFormat("[SCENE PRESENCE]: attachments {0}", attPoints.Count);
3106 int i = 0;
3107 AvatarAttachment[] attachs = new AvatarAttachment[attPoints.Count];
3108 foreach (int point in attPoints)
3109 {
3110 attachs[i++] = new AvatarAttachment(point, m_appearance.GetAttachedItem(point), m_appearance.GetAttachedAsset(point));
3111 }
3112 cAgent.Attachments = attachs;
3113 }
3114*/
3115 lock (scriptedcontrols) 3104 lock (scriptedcontrols)
3116 { 3105 {
3117 ControllerData[] controls = new ControllerData[scriptedcontrols.Count]; 3106 ControllerData[] controls = new ControllerData[scriptedcontrols.Count];
@@ -3131,9 +3120,26 @@ namespace OpenSim.Region.Framework.Scenes
3131 } 3120 }
3132 catch { } 3121 catch { }
3133 3122
3134 // cAgent.GroupID = ?? 3123 // Attachment objects
3135 // Groups??? 3124 if (m_attachments != null && m_attachments.Count > 0)
3136 3125 {
3126 cAgent.AttachmentObjects = new List<ISceneObject>();
3127 cAgent.AttachmentObjectStates = new List<string>();
3128 IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>();
3129 foreach (SceneObjectGroup sog in m_attachments)
3130 {
3131 // We need to make a copy and pass that copy
3132 // because of transfers withn the same sim
3133 ISceneObject clone = sog.CloneForNewScene();
3134 // Attachment module assumes that GroupPosition holds the offsets...!
3135 ((SceneObjectGroup)clone).RootPart.GroupPosition = sog.RootPart.AttachedPos;
3136 ((SceneObjectGroup)clone).RootPart.IsAttachment = false;
3137 cAgent.AttachmentObjects.Add(clone);
3138 cAgent.AttachmentObjectStates.Add(sog.GetStateSnapshot());
3139 // Let's remove the scripts of the original object here
3140 sog.RemoveScriptInstances(true);
3141 }
3142 }
3137 } 3143 }
3138 3144
3139 public void CopyFrom(AgentData cAgent) 3145 public void CopyFrom(AgentData cAgent)
@@ -3174,50 +3180,6 @@ namespace OpenSim.Region.Framework.Scenes
3174 AddToPhysicalScene(isFlying); 3180 AddToPhysicalScene(isFlying);
3175 } 3181 }
3176 3182
3177/*
3178 uint i = 0;
3179 try
3180 {
3181 if (cAgent.Wearables == null)
3182 cAgent.Wearables = new UUID[0];
3183 AvatarWearable[] wears = new AvatarWearable[cAgent.Wearables.Length / 2];
3184 for (uint n = 0; n < cAgent.Wearables.Length; n += 2)
3185 {
3186 UUID itemId = cAgent.Wearables[n];
3187 UUID assetId = cAgent.Wearables[n + 1];
3188 wears[i++] = new AvatarWearable(itemId, assetId);
3189 }
3190 // m_appearance.Wearables = wears;
3191 Primitive.TextureEntry textures = null;
3192 if (cAgent.AgentTextures != null && cAgent.AgentTextures.Length > 1)
3193 textures = new Primitive.TextureEntry(cAgent.AgentTextures, 0, cAgent.AgentTextures.Length);
3194
3195 byte[] visuals = null;
3196
3197 if ((cAgent.VisualParams != null) && (cAgent.VisualParams.Length < AvatarAppearance.VISUALPARAM_COUNT))
3198 visuals = (byte[])cAgent.VisualParams.Clone();
3199
3200 m_appearance = new AvatarAppearance(cAgent.AgentID,wears,textures,visuals);
3201 }
3202 catch (Exception e)
3203 {
3204 m_log.Warn("[SCENE PRESENCE]: exception in CopyFrom " + e.Message);
3205 }
3206
3207 // Attachments
3208 try
3209 {
3210 if (cAgent.Attachments != null)
3211 {
3212 m_appearance.ClearAttachments();
3213 foreach (AvatarAttachment att in cAgent.Attachments)
3214 {
3215 m_appearance.SetAttachment(att.AttachPoint, att.ItemID, att.AssetID);
3216 }
3217 }
3218 }
3219 catch { }
3220*/
3221 try 3183 try
3222 { 3184 {
3223 lock (scriptedcontrols) 3185 lock (scriptedcontrols)
@@ -3247,8 +3209,18 @@ namespace OpenSim.Region.Framework.Scenes
3247 } 3209 }
3248 catch { } 3210 catch { }
3249 3211
3250 //cAgent.GroupID = ?? 3212 if (cAgent.AttachmentObjects != null && cAgent.AttachmentObjects.Count > 0)
3251 //Groups??? 3213 {
3214 m_attachments = new List<SceneObjectGroup>();
3215 int i = 0;
3216 foreach (ISceneObject so in cAgent.AttachmentObjects)
3217 {
3218 ((SceneObjectGroup)so).LocalId = 0;
3219 ((SceneObjectGroup)so).RootPart.UpdateFlag = 0;
3220 so.SetState(cAgent.AttachmentObjectStates[i++], m_scene);
3221 m_scene.IncomingCreateObject(so);
3222 }
3223 }
3252 } 3224 }
3253 3225
3254 public bool CopyAgent(out IAgentData agent) 3226 public bool CopyAgent(out IAgentData agent)
@@ -3271,10 +3243,7 @@ namespace OpenSim.Region.Framework.Scenes
3271 3243
3272 m_updateflag = true; 3244 m_updateflag = true;
3273 3245
3274 // The magic constant 0.95f seems to make walking feel less jerky, 3246 Velocity = force;
3275 // probably because it hackishly accounts for the overall latency of
3276 // these Velocity updates -- Diva
3277 Velocity = force * .95F;
3278 3247
3279 m_forceToApply = null; 3248 m_forceToApply = null;
3280 } 3249 }
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
index 6a24cc1..db17d8f 100644
--- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -82,6 +82,14 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
82 m_scenes[scene.RegionInfo.RegionID] = scene; 82 m_scenes[scene.RegionInfo.RegionID] = scene;
83 83
84 scene.AddCommand( 84 scene.AddCommand(
85 this, "show pqueues",
86 "show pqueues [full]",
87 "Show priority queue data for each client",
88 "Without the 'full' option, only root agents are shown."
89 + " With the 'full' option child agents are also shown.",
90 ShowPQueuesReport);
91
92 scene.AddCommand(
85 this, "show queues", 93 this, "show queues",
86 "show queues [full]", 94 "show queues [full]",
87 "Show queue data for each client", 95 "Show queue data for each client",
@@ -119,6 +127,11 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
119// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 127// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
120 } 128 }
121 129
130 protected void ShowPQueuesReport(string module, string[] cmd)
131 {
132 MainConsole.Instance.Output(GetPQueuesReport(cmd));
133 }
134
122 protected void ShowQueuesReport(string module, string[] cmd) 135 protected void ShowQueuesReport(string module, string[] cmd)
123 { 136 {
124 MainConsole.Instance.Output(GetQueuesReport(cmd)); 137 MainConsole.Instance.Output(GetQueuesReport(cmd));
@@ -155,6 +168,80 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
155 ""); 168 "");
156 } 169 }
157 170
171
172 /// <summary>
173 /// Generate UDP Queue data report for each client
174 /// </summary>
175 /// <param name="showParams"></param>
176 /// <returns></returns>
177 protected string GetPQueuesReport(string[] showParams)
178 {
179 bool showChildren = false;
180 string pname = "";
181
182 if (showParams.Length > 2 && showParams[2] == "full")
183 showChildren = true;
184 else if (showParams.Length > 3)
185 pname = showParams[2] + " " + showParams[3];
186
187 StringBuilder report = new StringBuilder();
188
189 int columnPadding = 2;
190 int maxNameLength = 18;
191 int maxRegionNameLength = 14;
192 int maxTypeLength = 4;
193 int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
194
195 report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
196 report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
197 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
198
199 report.AppendFormat(
200 "{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7} {10,7} {11,7}\n",
201 "Pri 0",
202 "Pri 1",
203 "Pri 2",
204 "Pri 3",
205 "Pri 4",
206 "Pri 5",
207 "Pri 6",
208 "Pri 7",
209 "Pri 8",
210 "Pri 9",
211 "Pri 10",
212 "Pri 11");
213
214 lock (m_scenes)
215 {
216 foreach (Scene scene in m_scenes.Values)
217 {
218 scene.ForEachClient(
219 delegate(IClientAPI client)
220 {
221 if (client is LLClientView)
222 {
223 bool isChild = scene.PresenceChildStatus(client.AgentId);
224 if (isChild && !showChildren)
225 return;
226
227 string name = client.Name;
228 if (pname != "" && name != pname)
229 return;
230
231 string regionName = scene.RegionInfo.RegionName;
232
233 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
234 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
235 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
236 report.AppendLine(((LLClientView)client).EntityUpdateQueue.ToString());
237 }
238 });
239 }
240 }
241
242 return report.ToString();
243 }
244
158 /// <summary> 245 /// <summary>
159 /// Generate UDP Queue data report for each client 246 /// Generate UDP Queue data report for each client
160 /// </summary> 247 /// </summary>
@@ -163,10 +250,13 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
163 protected string GetQueuesReport(string[] showParams) 250 protected string GetQueuesReport(string[] showParams)
164 { 251 {
165 bool showChildren = false; 252 bool showChildren = false;
253 string pname = "";
166 254
167 if (showParams.Length > 2 && showParams[2] == "full") 255 if (showParams.Length > 2 && showParams[2] == "full")
168 showChildren = true; 256 showChildren = true;
169 257 else if (showParams.Length > 3)
258 pname = showParams[2] + " " + showParams[3];
259
170 StringBuilder report = new StringBuilder(); 260 StringBuilder report = new StringBuilder();
171 261
172 int columnPadding = 2; 262 int columnPadding = 2;
@@ -224,6 +314,9 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
224 return; 314 return;
225 315
226 string name = client.Name; 316 string name = client.Name;
317 if (pname != "" && name != pname)
318 return;
319
227 string regionName = scene.RegionInfo.RegionName; 320 string regionName = scene.RegionInfo.RegionName;
228 321
229 report.Append(GetColumnEntry(name, maxNameLength, columnPadding)); 322 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
@@ -249,10 +342,13 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
249 protected string GetThrottlesReport(string[] showParams) 342 protected string GetThrottlesReport(string[] showParams)
250 { 343 {
251 bool showChildren = false; 344 bool showChildren = false;
345 string pname = "";
252 346
253 if (showParams.Length > 2 && showParams[2] == "full") 347 if (showParams.Length > 2 && showParams[2] == "full")
254 showChildren = true; 348 showChildren = true;
255 349 else if (showParams.Length > 3)
350 pname = showParams[2] + " " + showParams[3];
351
256 StringBuilder report = new StringBuilder(); 352 StringBuilder report = new StringBuilder();
257 353
258 int columnPadding = 2; 354 int columnPadding = 2;
@@ -302,7 +398,7 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
302 if (client is LLClientView) 398 if (client is LLClientView)
303 { 399 {
304 LLClientView llClient = client as LLClientView; 400 LLClientView llClient = client as LLClientView;
305 401
306 if (firstClient) 402 if (firstClient)
307 { 403 {
308 report.AppendLine(GetServerThrottlesReport(llClient.UDPServer)); 404 report.AppendLine(GetServerThrottlesReport(llClient.UDPServer));
@@ -314,6 +410,9 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
314 return; 410 return;
315 411
316 string name = client.Name; 412 string name = client.Name;
413 if (pname != "" && name != pname)
414 return;
415
317 string regionName = scene.RegionInfo.RegionName; 416 string regionName = scene.RegionInfo.RegionName;
318 417
319 LLUDPClient llUdpClient = llClient.UDPClient; 418 LLUDPClient llUdpClient = llClient.UDPClient;
@@ -352,7 +451,7 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
352 int maxRegionNameLength = 14; 451 int maxRegionNameLength = 14;
353 int maxTypeLength = 4; 452 int maxTypeLength = 4;
354 453
355 string name = "SERVER AGENT LIMITS"; 454 string name = "SERVER AGENT RATES";
356 455
357 report.Append(GetColumnEntry(name, maxNameLength, columnPadding)); 456 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
358 report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding)); 457 report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding));
@@ -362,13 +461,13 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
362 report.AppendFormat( 461 report.AppendFormat(
363 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}", 462 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}",
364 (throttleRates.Total * 8) / 1000, 463 (throttleRates.Total * 8) / 1000,
365 (throttleRates.ResendLimit * 8) / 1000, 464 (throttleRates.Resend * 8) / 1000,
366 (throttleRates.LandLimit * 8) / 1000, 465 (throttleRates.Land * 8) / 1000,
367 (throttleRates.WindLimit * 8) / 1000, 466 (throttleRates.Wind * 8) / 1000,
368 (throttleRates.CloudLimit * 8) / 1000, 467 (throttleRates.Cloud * 8) / 1000,
369 (throttleRates.TaskLimit * 8) / 1000, 468 (throttleRates.Task * 8) / 1000,
370 (throttleRates.TextureLimit * 8) / 1000, 469 (throttleRates.Texture * 8) / 1000,
371 (throttleRates.AssetLimit * 8) / 1000); 470 (throttleRates.Asset * 8) / 1000);
372 471
373 return report.ToString(); 472 return report.ToString();
374 } 473 }
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index 64774d8..f89b824 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -88,7 +88,8 @@ namespace OpenSim.Region.Physics.Meshing
88 88
89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); 89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); 90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
91 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); 91 if(mesh_config != null)
92 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
92 93
93 try 94 try
94 { 95 {