diff options
Diffstat (limited to '')
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; | |||
34 | using OpenSim.Framework.Client; | 34 | using OpenSim.Framework.Client; |
35 | using log4net; | 35 | using log4net; |
36 | 36 | ||
37 | namespace OpenSim.Region.ClientStack.LindenUDP | 37 | namespace 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 | ||
32 | namespace OpenSim.Region.ClientStack.LindenUDP | 32 | namespace 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; | |||
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using OpenSim.Framework; | ||
33 | |||
32 | using log4net; | 34 | using log4net; |
33 | 35 | ||
34 | namespace OpenSim.Region.ClientStack.LindenUDP | 36 | namespace 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 | { |