diff options
17 files changed, 410 insertions, 193 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 14c5d6c..1108863 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -3567,7 +3567,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3567 | /// with any other updates that may be queued for the same entity. | 3567 | /// with any other updates that may be queued for the same entity. |
3568 | /// The original update time is used for the merged update. | 3568 | /// The original update time is used for the merged update. |
3569 | /// </summary> | 3569 | /// </summary> |
3570 | public void ResendPrimUpdate(EntityUpdate update) | 3570 | private void ResendPrimUpdate(EntityUpdate update) |
3571 | { | 3571 | { |
3572 | // If the update exists in priority queue, it will be updated. | 3572 | // If the update exists in priority queue, it will be updated. |
3573 | // If it does not exist then it will be added with the current (rather than its original) priority | 3573 | // If it does not exist then it will be added with the current (rather than its original) priority |
@@ -3583,8 +3583,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3583 | /// with any other updates that may be queued for the same entity. | 3583 | /// with any other updates that may be queued for the same entity. |
3584 | /// The original update time is used for the merged update. | 3584 | /// The original update time is used for the merged update. |
3585 | /// </summary> | 3585 | /// </summary> |
3586 | void ResendPrimUpdates(List<EntityUpdate> updates) | 3586 | private void ResendPrimUpdates(List<EntityUpdate> updates) |
3587 | { | 3587 | { |
3588 | // m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime); | ||
3589 | |||
3588 | foreach (EntityUpdate update in updates) | 3590 | foreach (EntityUpdate update in updates) |
3589 | ResendPrimUpdate(update); | 3591 | ResendPrimUpdate(update); |
3590 | } | 3592 | } |
@@ -4018,6 +4020,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4018 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); | 4020 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); |
4019 | } | 4021 | } |
4020 | 4022 | ||
4023 | private void ResendPropertyUpdate(ObjectPropertyUpdate update) | ||
4024 | { | ||
4025 | uint priority = 0; | ||
4026 | lock (m_entityProps.SyncRoot) | ||
4027 | m_entityProps.Enqueue(priority, update); | ||
4028 | } | ||
4029 | |||
4030 | private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates) | ||
4031 | { | ||
4032 | // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime); | ||
4033 | |||
4034 | foreach (ObjectPropertyUpdate update in updates) | ||
4035 | ResendPropertyUpdate(update); | ||
4036 | } | ||
4037 | |||
4021 | public void SendObjectPropertiesReply(ISceneEntity entity) | 4038 | public void SendObjectPropertiesReply(ISceneEntity entity) |
4022 | { | 4039 | { |
4023 | uint priority = 0; // time based ordering only | 4040 | uint priority = 0; // time based ordering only |
@@ -4033,6 +4050,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4033 | OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = | 4050 | OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = |
4034 | new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); | 4051 | new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); |
4035 | 4052 | ||
4053 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates = | ||
4054 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4055 | |||
4056 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates = | ||
4057 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4058 | |||
4036 | IEntityUpdate iupdate; | 4059 | IEntityUpdate iupdate; |
4037 | Int32 timeinqueue; // this is just debugging code & can be dropped later | 4060 | Int32 timeinqueue; // this is just debugging code & can be dropped later |
4038 | 4061 | ||
@@ -4051,6 +4074,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4051 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | 4074 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
4052 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); | 4075 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); |
4053 | objectFamilyBlocks.Value.Add(objPropDB); | 4076 | objectFamilyBlocks.Value.Add(objPropDB); |
4077 | familyUpdates.Value.Add(update); | ||
4054 | } | 4078 | } |
4055 | } | 4079 | } |
4056 | 4080 | ||
@@ -4061,6 +4085,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4061 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | 4085 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
4062 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); | 4086 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); |
4063 | objectPropertiesBlocks.Value.Add(objPropDB); | 4087 | objectPropertiesBlocks.Value.Add(objPropDB); |
4088 | propertyUpdates.Value.Add(update); | ||
4064 | } | 4089 | } |
4065 | } | 4090 | } |
4066 | 4091 | ||
@@ -4068,12 +4093,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4068 | } | 4093 | } |
4069 | 4094 | ||
4070 | 4095 | ||
4071 | Int32 ppcnt = 0; | 4096 | // Int32 ppcnt = 0; |
4072 | Int32 pbcnt = 0; | 4097 | // Int32 pbcnt = 0; |
4073 | 4098 | ||
4074 | if (objectPropertiesBlocks.IsValueCreated) | 4099 | if (objectPropertiesBlocks.IsValueCreated) |
4075 | { | 4100 | { |
4076 | List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; | 4101 | List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; |
4102 | List<ObjectPropertyUpdate> updates = propertyUpdates.Value; | ||
4077 | 4103 | ||
4078 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 4104 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
4079 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; | 4105 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; |
@@ -4081,28 +4107,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4081 | packet.ObjectData[i] = blocks[i]; | 4107 | packet.ObjectData[i] = blocks[i]; |
4082 | 4108 | ||
4083 | packet.Header.Zerocoded = true; | 4109 | packet.Header.Zerocoded = true; |
4084 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4085 | 4110 | ||
4086 | pbcnt += blocks.Count; | 4111 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties |
4087 | ppcnt++; | 4112 | // of the object rather than the properties when the packet was created |
4113 | OutPacket(packet, ThrottleOutPacketType.Task, true, | ||
4114 | delegate() | ||
4115 | { | ||
4116 | ResendPropertyUpdates(updates); | ||
4117 | }); | ||
4118 | |||
4119 | // pbcnt += blocks.Count; | ||
4120 | // ppcnt++; | ||
4088 | } | 4121 | } |
4089 | 4122 | ||
4090 | Int32 fpcnt = 0; | 4123 | // Int32 fpcnt = 0; |
4091 | Int32 fbcnt = 0; | 4124 | // Int32 fbcnt = 0; |
4092 | 4125 | ||
4093 | if (objectFamilyBlocks.IsValueCreated) | 4126 | if (objectFamilyBlocks.IsValueCreated) |
4094 | { | 4127 | { |
4095 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; | 4128 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; |
4096 | 4129 | List<ObjectPropertyUpdate> updates = familyUpdates.Value; | |
4097 | // ObjectPropertiesFamilyPacket objPropFamilyPack = | 4130 | |
4098 | // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); | ||
4099 | // | ||
4100 | // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count]; | ||
4101 | // for (int i = 0; i < blocks.Count; i++) | ||
4102 | // objPropFamilyPack.ObjectData[i] = blocks[i]; | ||
4103 | // | ||
4104 | // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true); | ||
4105 | |||
4106 | // one packet per object block... uggh... | 4131 | // one packet per object block... uggh... |
4107 | for (int i = 0; i < blocks.Count; i++) | 4132 | for (int i = 0; i < blocks.Count; i++) |
4108 | { | 4133 | { |
@@ -4111,10 +4136,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4111 | 4136 | ||
4112 | packet.ObjectData = blocks[i]; | 4137 | packet.ObjectData = blocks[i]; |
4113 | packet.Header.Zerocoded = true; | 4138 | packet.Header.Zerocoded = true; |
4114 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4115 | 4139 | ||
4116 | fpcnt++; | 4140 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties |
4117 | fbcnt++; | 4141 | // of the object rather than the properties when the packet was created |
4142 | ObjectPropertyUpdate update = updates[i]; | ||
4143 | OutPacket(packet, ThrottleOutPacketType.Task, true, | ||
4144 | delegate() | ||
4145 | { | ||
4146 | ResendPropertyUpdate(update); | ||
4147 | }); | ||
4148 | |||
4149 | // fpcnt++; | ||
4150 | // fbcnt++; | ||
4118 | } | 4151 | } |
4119 | 4152 | ||
4120 | } | 4153 | } |
@@ -4151,7 +4184,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4151 | 4184 | ||
4152 | return block; | 4185 | return block; |
4153 | } | 4186 | } |
4154 | 4187 | ||
4155 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) | 4188 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) |
4156 | { | 4189 | { |
4157 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 4190 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 7be8a0a..20bfec8 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,7 +181,7 @@ 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.TotalLimit); |
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, rates.TotalLimit); |
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 |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 07b0a1d..4ee6d3a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | |||
@@ -48,31 +48,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
48 | /// Number of ticks (ms) per quantum, drip rate and max burst | 48 | /// Number of ticks (ms) per quantum, drip rate and max burst |
49 | /// are defined over this interval. | 49 | /// are defined over this interval. |
50 | /// </summary> | 50 | /// </summary> |
51 | private const Int32 m_ticksPerQuantum = 1000; | 51 | protected const Int32 m_ticksPerQuantum = 1000; |
52 | 52 | ||
53 | /// <summary> | 53 | /// <summary> |
54 | /// This is the number of quantums worth of packets that can | 54 | /// This is the number of quantums worth of packets that can |
55 | /// be accommodated during a burst | 55 | /// be accommodated during a burst |
56 | /// </summary> | 56 | /// </summary> |
57 | private const Double m_quantumsPerBurst = 1.5; | 57 | protected const Double m_quantumsPerBurst = 1.5; |
58 | 58 | ||
59 | /// <summary> | 59 | /// <summary> |
60 | /// </summary> | 60 | /// </summary> |
61 | private const Int32 m_minimumDripRate = 1400; | 61 | protected const Int32 m_minimumDripRate = 1400; |
62 | 62 | ||
63 | /// <summary>Time of the last drip, in system ticks</summary> | 63 | /// <summary>Time of the last drip, in system ticks</summary> |
64 | private Int32 m_lastDrip; | 64 | protected Int32 m_lastDrip; |
65 | 65 | ||
66 | /// <summary> | 66 | /// <summary> |
67 | /// The number of bytes that can be sent at this moment. This is the | 67 | /// The number of bytes that can be sent at this moment. This is the |
68 | /// current number of tokens in the bucket | 68 | /// current number of tokens in the bucket |
69 | /// </summary> | 69 | /// </summary> |
70 | private Int64 m_tokenCount; | 70 | protected Int64 m_tokenCount; |
71 | 71 | ||
72 | /// <summary> | 72 | /// <summary> |
73 | /// Map of children buckets and their requested maximum burst rate | 73 | /// Map of children buckets and their requested maximum burst rate |
74 | /// </summary> | 74 | /// </summary> |
75 | private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | 75 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); |
76 | 76 | ||
77 | #region Properties | 77 | #region Properties |
78 | 78 | ||
@@ -81,7 +81,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
81 | /// parent. The parent bucket will limit the aggregate bandwidth of all | 81 | /// parent. The parent bucket will limit the aggregate bandwidth of all |
82 | /// of its children buckets | 82 | /// of its children buckets |
83 | /// </summary> | 83 | /// </summary> |
84 | private TokenBucket m_parent; | 84 | protected TokenBucket m_parent; |
85 | public TokenBucket Parent | 85 | public TokenBucket Parent |
86 | { | 86 | { |
87 | get { return m_parent; } | 87 | get { return m_parent; } |
@@ -93,7 +93,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
93 | /// of tokens that can accumulate in the bucket at any one time. This | 93 | /// of tokens that can accumulate in the bucket at any one time. This |
94 | /// also sets the total request for leaf nodes | 94 | /// also sets the total request for leaf nodes |
95 | /// </summary> | 95 | /// </summary> |
96 | private Int64 m_burstRate; | 96 | protected Int64 m_burstRate; |
97 | public Int64 RequestedBurstRate | 97 | public Int64 RequestedBurstRate |
98 | { | 98 | { |
99 | get { return m_burstRate; } | 99 | get { return m_burstRate; } |
@@ -118,8 +118,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
118 | /// <remarks>Tokens are added to the bucket any time | 118 | /// <remarks>Tokens are added to the bucket any time |
119 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | 119 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of |
120 | /// the system tick interval (typically around 15-22ms)</remarks> | 120 | /// the system tick interval (typically around 15-22ms)</remarks> |
121 | private Int64 m_dripRate; | 121 | protected Int64 m_dripRate; |
122 | public Int64 RequestedDripRate | 122 | public virtual Int64 RequestedDripRate |
123 | { | 123 | { |
124 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } | 124 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } |
125 | set { | 125 | set { |
@@ -131,7 +131,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
131 | } | 131 | } |
132 | } | 132 | } |
133 | 133 | ||
134 | public Int64 DripRate | 134 | public virtual Int64 DripRate |
135 | { | 135 | { |
136 | get { | 136 | get { |
137 | if (m_parent == null) | 137 | if (m_parent == null) |
@@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
149 | /// The current total of the requested maximum burst rates of | 149 | /// The current total of the requested maximum burst rates of |
150 | /// this bucket's children buckets. | 150 | /// this bucket's children buckets. |
151 | /// </summary> | 151 | /// </summary> |
152 | private Int64 m_totalDripRequest; | 152 | protected Int64 m_totalDripRequest; |
153 | public Int64 TotalDripRequest | 153 | public Int64 TotalDripRequest |
154 | { | 154 | { |
155 | get { return m_totalDripRequest; } | 155 | get { return m_totalDripRequest; } |
@@ -189,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
189 | /// hierarchy. However, if any of the parents is over-booked, then | 189 | /// hierarchy. However, if any of the parents is over-booked, then |
190 | /// the modifier will be less than 1. | 190 | /// the modifier will be less than 1. |
191 | /// </summary> | 191 | /// </summary> |
192 | private double DripRateModifier() | 192 | protected double DripRateModifier() |
193 | { | 193 | { |
194 | Int64 driprate = DripRate; | 194 | Int64 driprate = DripRate; |
195 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | 195 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; |
@@ -197,7 +197,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
197 | 197 | ||
198 | /// <summary> | 198 | /// <summary> |
199 | /// </summary> | 199 | /// </summary> |
200 | private double BurstRateModifier() | 200 | protected double BurstRateModifier() |
201 | { | 201 | { |
202 | // for now... burst rate is always m_quantumsPerBurst (constant) | 202 | // for now... burst rate is always m_quantumsPerBurst (constant) |
203 | // larger than drip rate so the ratio of burst requests is the | 203 | // larger than drip rate so the ratio of burst requests is the |
@@ -268,7 +268,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
268 | /// Deposit tokens into the bucket from a child bucket that did | 268 | /// Deposit tokens into the bucket from a child bucket that did |
269 | /// not use all of its available tokens | 269 | /// not use all of its available tokens |
270 | /// </summary> | 270 | /// </summary> |
271 | private void Deposit(Int64 count) | 271 | protected void Deposit(Int64 count) |
272 | { | 272 | { |
273 | m_tokenCount += count; | 273 | m_tokenCount += count; |
274 | 274 | ||
@@ -285,7 +285,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
285 | /// call to Drip | 285 | /// call to Drip |
286 | /// </summary> | 286 | /// </summary> |
287 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> | 287 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> |
288 | private void Drip() | 288 | protected void Drip() |
289 | { | 289 | { |
290 | // This should never happen... means we are a leaf node and were created | 290 | // This should never happen... means we are a leaf node and were created |
291 | // with no drip rate... | 291 | // with no drip rate... |
@@ -310,4 +310,64 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
310 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); | 310 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); |
311 | } | 311 | } |
312 | } | 312 | } |
313 | |||
314 | public class AdaptiveTokenBucket : TokenBucket | ||
315 | { | ||
316 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
317 | |||
318 | // <summary> | ||
319 | // The minimum rate for flow control. | ||
320 | // </summary> | ||
321 | protected const Int64 m_minimumFlow = m_minimumDripRate * 10; | ||
322 | |||
323 | // <summary> | ||
324 | // The maximum rate for flow control. Drip rate can never be | ||
325 | // greater than this. | ||
326 | // </summary> | ||
327 | protected Int64 m_maxDripRate = 0; | ||
328 | protected Int64 MaxDripRate | ||
329 | { | ||
330 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } | ||
331 | set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); } | ||
332 | } | ||
333 | |||
334 | // <summary> | ||
335 | // | ||
336 | // </summary> | ||
337 | public virtual Int64 AdjustedDripRate | ||
338 | { | ||
339 | get { return m_dripRate; } | ||
340 | set { | ||
341 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); | ||
342 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | ||
343 | if (m_parent != null) | ||
344 | m_parent.RegisterRequest(this,m_dripRate); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | // <summary> | ||
349 | // | ||
350 | // </summary> | ||
351 | public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate) : base(parent,m_minimumFlow) | ||
352 | { | ||
353 | MaxDripRate = maxDripRate; | ||
354 | } | ||
355 | |||
356 | // <summary> | ||
357 | // | ||
358 | // </summary> | ||
359 | public void ExpirePackets(Int32 count) | ||
360 | { | ||
361 | // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); | ||
362 | AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count)); | ||
363 | } | ||
364 | |||
365 | // <summary> | ||
366 | // | ||
367 | // </summary> | ||
368 | public void AcknowledgePackets(Int32 count) | ||
369 | { | ||
370 | AdjustedDripRate = AdjustedDripRate + count; | ||
371 | } | ||
372 | } | ||
313 | } | 373 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index d195110..b170964 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | |||
@@ -130,6 +130,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
130 | // is actually sent out again | 130 | // is actually sent out again |
131 | packet.TickCount = 0; | 131 | packet.TickCount = 0; |
132 | 132 | ||
133 | // As with other network applications, assume that an expired packet is | ||
134 | // an indication of some network problem, slow transmission | ||
135 | packet.Client.FlowThrottle.ExpirePackets(1); | ||
136 | |||
133 | expiredPackets.Add(packet); | 137 | expiredPackets.Add(packet); |
134 | } | 138 | } |
135 | } | 139 | } |
@@ -157,6 +161,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
157 | { | 161 | { |
158 | m_packets.Remove(pendingRemove.SequenceNumber); | 162 | m_packets.Remove(pendingRemove.SequenceNumber); |
159 | 163 | ||
164 | // As with other network applications, assume that an acknowledged packet is an | ||
165 | // indication that the network can handle a little more load, speed up the transmission | ||
166 | ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength); | ||
167 | |||
160 | // Update stats | 168 | // Update stats |
161 | Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); | 169 | Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); |
162 | 170 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs index d2278bc..deec444 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/GetMeshModule.cs | |||
@@ -66,12 +66,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets | |||
66 | 66 | ||
67 | public void Initialise(IConfigSource source) | 67 | public void Initialise(IConfigSource source) |
68 | { | 68 | { |
69 | IConfig startupConfig = source.Configs["Startup"]; | 69 | IConfig meshConfig = source.Configs["Mesh"]; |
70 | if (startupConfig == null) | 70 | if (meshConfig == null) |
71 | return; | 71 | return; |
72 | 72 | ||
73 | if (!startupConfig.GetBoolean("ColladaMesh",true)) | 73 | m_enabled = meshConfig.GetBoolean("ColladaMesh", true); |
74 | m_enabled = false; | ||
75 | } | 74 | } |
76 | 75 | ||
77 | public void AddRegion(Scene pScene) | 76 | public void AddRegion(Scene pScene) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs index fb07cc9..d651cb2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Assets/NewFileAgentInventoryVariablePriceModule.cs | |||
@@ -68,12 +68,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Assets | |||
68 | 68 | ||
69 | public void Initialise(IConfigSource source) | 69 | public void Initialise(IConfigSource source) |
70 | { | 70 | { |
71 | IConfig startupConfig = source.Configs["Startup"]; | 71 | IConfig meshConfig = source.Configs["Mesh"]; |
72 | if (startupConfig == null) | 72 | if (meshConfig == null) |
73 | return; | 73 | return; |
74 | 74 | ||
75 | if (!startupConfig.GetBoolean("ColladaMesh",true)) | 75 | m_enabled = meshConfig.GetBoolean("ColladaMesh", true); |
76 | m_enabled = false; | ||
77 | } | 76 | } |
78 | 77 | ||
79 | public void AddRegion(Scene pScene) | 78 | public void AddRegion(Scene pScene) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index f3d2f26..6b24718 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs | |||
@@ -78,11 +78,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
78 | private Stream m_loadStream; | 78 | private Stream m_loadStream; |
79 | 79 | ||
80 | /// <summary> | 80 | /// <summary> |
81 | /// FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things | 81 | /// Has the control file been loaded for this archive? |
82 | /// (I thought they weren't). We will need to bump the version number and perform this check on all | ||
83 | /// subsequent IAR versions only | ||
84 | /// </summary> | 82 | /// </summary> |
85 | protected bool m_controlFileLoaded = true; | 83 | public bool ControlFileLoaded { get; private set; } |
84 | |||
85 | /// <summary> | ||
86 | /// Do we want to enforce the check. IAR versions before 0.2 and 1.1 do not guarantee this order, so we can't | ||
87 | /// enforce. | ||
88 | /// </summary> | ||
89 | public bool EnforceControlFileCheck { get; private set; } | ||
90 | |||
86 | protected bool m_assetsLoaded; | 91 | protected bool m_assetsLoaded; |
87 | protected bool m_inventoryNodesLoaded; | 92 | protected bool m_inventoryNodesLoaded; |
88 | 93 | ||
@@ -131,6 +136,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
131 | m_userInfo = userInfo; | 136 | m_userInfo = userInfo; |
132 | m_invPath = invPath; | 137 | m_invPath = invPath; |
133 | m_loadStream = loadStream; | 138 | m_loadStream = loadStream; |
139 | |||
140 | // FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things | ||
141 | // (I thought they weren't). We will need to bump the version number and perform this check on all | ||
142 | // subsequent IAR versions only | ||
143 | ControlFileLoaded = true; | ||
134 | } | 144 | } |
135 | 145 | ||
136 | /// <summary> | 146 | /// <summary> |
@@ -522,7 +532,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
522 | /// </summary> | 532 | /// </summary> |
523 | /// <param name="path"></param> | 533 | /// <param name="path"></param> |
524 | /// <param name="data"></param> | 534 | /// <param name="data"></param> |
525 | protected void LoadControlFile(string path, byte[] data) | 535 | public void LoadControlFile(string path, byte[] data) |
526 | { | 536 | { |
527 | XDocument doc = XDocument.Parse(Encoding.ASCII.GetString(data)); | 537 | XDocument doc = XDocument.Parse(Encoding.ASCII.GetString(data)); |
528 | XElement archiveElement = doc.Element("archive"); | 538 | XElement archiveElement = doc.Element("archive"); |
@@ -538,7 +548,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
538 | majorVersion, MAX_MAJOR_VERSION)); | 548 | majorVersion, MAX_MAJOR_VERSION)); |
539 | } | 549 | } |
540 | 550 | ||
541 | m_controlFileLoaded = true; | 551 | ControlFileLoaded = true; |
542 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Loading IAR with version {0}", version); | 552 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Loading IAR with version {0}", version); |
543 | } | 553 | } |
544 | 554 | ||
@@ -550,7 +560,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
550 | /// <param name="data"></param> | 560 | /// <param name="data"></param> |
551 | protected void LoadInventoryFile(string path, TarArchiveReader.TarEntryType entryType, byte[] data) | 561 | protected void LoadInventoryFile(string path, TarArchiveReader.TarEntryType entryType, byte[] data) |
552 | { | 562 | { |
553 | if (!m_controlFileLoaded) | 563 | if (!ControlFileLoaded) |
554 | throw new Exception( | 564 | throw new Exception( |
555 | string.Format( | 565 | string.Format( |
556 | "The IAR you are trying to load does not list {0} before {1}. Aborting load", | 566 | "The IAR you are trying to load does not list {0} before {1}. Aborting load", |
@@ -597,7 +607,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
597 | /// <param name="data"></param> | 607 | /// <param name="data"></param> |
598 | protected void LoadAssetFile(string path, byte[] data) | 608 | protected void LoadAssetFile(string path, byte[] data) |
599 | { | 609 | { |
600 | if (!m_controlFileLoaded) | 610 | if (!ControlFileLoaded) |
601 | throw new Exception( | 611 | throw new Exception( |
602 | string.Format( | 612 | string.Format( |
603 | "The IAR you are trying to load does not list {0} before {1}. Aborting load", | 613 | "The IAR you are trying to load does not list {0} before {1}. Aborting load", |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index dc4900f..c039b5a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs | |||
@@ -394,12 +394,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
394 | if (options.ContainsKey("profile")) | 394 | if (options.ContainsKey("profile")) |
395 | { | 395 | { |
396 | majorVersion = 1; | 396 | majorVersion = 1; |
397 | minorVersion = 0; | 397 | minorVersion = 1; |
398 | } | 398 | } |
399 | else | 399 | else |
400 | { | 400 | { |
401 | majorVersion = 0; | 401 | majorVersion = 0; |
402 | minorVersion = 1; | 402 | minorVersion = 2; |
403 | } | 403 | } |
404 | 404 | ||
405 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Creating version {0}.{1} IAR", majorVersion, minorVersion); | 405 | m_log.InfoFormat("[INVENTORY ARCHIVER]: Creating version {0}.{1} IAR", majorVersion, minorVersion); |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index d03f6da..52232a0 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs | |||
@@ -94,7 +94,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
94 | 94 | ||
95 | Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); | 95 | Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); |
96 | Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); | 96 | Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); |
97 | } | 97 | } |
98 | |||
99 | /// <summary> | ||
100 | /// Test that the IAR has the required files in the right order. | ||
101 | /// </summary> | ||
102 | /// <remarks> | ||
103 | /// At the moment, the only thing that matters is that the control file is the very first one. | ||
104 | /// </remarks> | ||
105 | [Test] | ||
106 | public void TestOrder() | ||
107 | { | ||
108 | TestHelper.InMethod(); | ||
109 | // log4net.Config.XmlConfigurator.Configure(); | ||
110 | |||
111 | MemoryStream archiveReadStream = new MemoryStream(m_iarStreamBytes); | ||
112 | TarArchiveReader tar = new TarArchiveReader(archiveReadStream); | ||
113 | string filePath; | ||
114 | TarArchiveReader.TarEntryType tarEntryType; | ||
115 | |||
116 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | ||
117 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | ||
118 | |||
119 | InventoryArchiveReadRequest iarr | ||
120 | = new InventoryArchiveReadRequest(null, null, null, (Stream)null, false); | ||
121 | iarr.LoadControlFile(filePath, data); | ||
122 | |||
123 | Assert.That(iarr.ControlFileLoaded, Is.True); | ||
124 | } | ||
98 | 125 | ||
99 | /// <summary> | 126 | /// <summary> |
100 | /// Test saving a single inventory item to a V0.1 OpenSim Inventory Archive | 127 | /// Test saving a single inventory item to a V0.1 OpenSim Inventory Archive |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 8c99983..52791cb 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs | |||
@@ -75,6 +75,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
75 | if (name == Name) | 75 | if (name == Name) |
76 | { | 76 | { |
77 | m_Enabled = true; | 77 | m_Enabled = true; |
78 | |||
79 | InitialiseCommon(source); | ||
80 | |||
78 | m_log.InfoFormat("[HG INVENTORY ACCESS MODULE]: {0} enabled.", Name); | 81 | m_log.InfoFormat("[HG INVENTORY ACCESS MODULE]: {0} enabled.", Name); |
79 | 82 | ||
80 | IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; | 83 | IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index a716326..6b3df9d 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | |||
@@ -64,7 +64,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
64 | return m_UserManagement; | 64 | return m_UserManagement; |
65 | } | 65 | } |
66 | } | 66 | } |
67 | 67 | ||
68 | public bool CoalesceMultipleObjectsToInventory { get; set; } | ||
68 | 69 | ||
69 | #region INonSharedRegionModule | 70 | #region INonSharedRegionModule |
70 | 71 | ||
@@ -87,10 +88,28 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
87 | if (name == Name) | 88 | if (name == Name) |
88 | { | 89 | { |
89 | m_Enabled = true; | 90 | m_Enabled = true; |
90 | m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); | 91 | |
92 | InitialiseCommon(source); | ||
93 | |||
94 | m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); | ||
91 | } | 95 | } |
92 | } | 96 | } |
93 | } | 97 | } |
98 | |||
99 | /// <summary> | ||
100 | /// Common module config for both this and descendant classes. | ||
101 | /// </summary> | ||
102 | /// <param name="source"></param> | ||
103 | protected virtual void InitialiseCommon(IConfigSource source) | ||
104 | { | ||
105 | IConfig inventoryConfig = source.Configs["Inventory"]; | ||
106 | |||
107 | if (inventoryConfig != null) | ||
108 | CoalesceMultipleObjectsToInventory | ||
109 | = inventoryConfig.GetBoolean("CoalesceMultipleObjectsToInventory", true); | ||
110 | else | ||
111 | CoalesceMultipleObjectsToInventory = true; | ||
112 | } | ||
94 | 113 | ||
95 | public virtual void PostInitialise() | 114 | public virtual void PostInitialise() |
96 | { | 115 | { |
@@ -194,32 +213,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
194 | 213 | ||
195 | return UUID.Zero; | 214 | return UUID.Zero; |
196 | } | 215 | } |
197 | 216 | ||
198 | /// <summary> | 217 | public virtual UUID CopyToInventory(DeRezAction action, UUID folderID, |
199 | /// Delete a scene object from a scene and place in the given avatar's inventory. | ||
200 | /// Returns the UUID of the newly created asset. | ||
201 | /// </summary> | ||
202 | /// <param name="action"></param> | ||
203 | /// <param name="folderID"></param> | ||
204 | /// <param name="objectGroup"></param> | ||
205 | /// <param name="remoteClient"> </param> | ||
206 | public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID, | ||
207 | List<SceneObjectGroup> objectGroups, IClientAPI remoteClient) | 218 | List<SceneObjectGroup> objectGroups, IClientAPI remoteClient) |
208 | { | 219 | { |
209 | UUID ret = UUID.Zero; | 220 | Dictionary<UUID, List<SceneObjectGroup>> bundlesToCopy = new Dictionary<UUID, List<SceneObjectGroup>>(); |
210 | 221 | ||
211 | // The following code groups the SOG's by owner. No objects | 222 | if (CoalesceMultipleObjectsToInventory) |
212 | // belonging to different people can be coalesced, for obvious | ||
213 | // reasons. | ||
214 | Dictionary<UUID, List<SceneObjectGroup>> deletes = | ||
215 | new Dictionary<UUID, List<SceneObjectGroup>>(); | ||
216 | |||
217 | foreach (SceneObjectGroup g in objectGroups) | ||
218 | { | 223 | { |
219 | if (!deletes.ContainsKey(g.OwnerID)) | 224 | // The following code groups the SOG's by owner. No objects |
220 | deletes[g.OwnerID] = new List<SceneObjectGroup>(); | 225 | // belonging to different people can be coalesced, for obvious |
221 | 226 | // reasons. | |
222 | deletes[g.OwnerID].Add(g); | 227 | foreach (SceneObjectGroup g in objectGroups) |
228 | { | ||
229 | if (!bundlesToCopy.ContainsKey(g.OwnerID)) | ||
230 | bundlesToCopy[g.OwnerID] = new List<SceneObjectGroup>(); | ||
231 | |||
232 | bundlesToCopy[g.OwnerID].Add(g); | ||
233 | } | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | // If we don't want to coalesce then put every object in its own bundle. | ||
238 | foreach (SceneObjectGroup g in objectGroups) | ||
239 | { | ||
240 | List<SceneObjectGroup> bundle = new List<SceneObjectGroup>(); | ||
241 | bundle.Add(g); | ||
242 | bundlesToCopy[g.UUID] = bundle; | ||
243 | } | ||
223 | } | 244 | } |
224 | 245 | ||
225 | // This is method scoped and will be returned. It will be the | 246 | // This is method scoped and will be returned. It will be the |
@@ -228,112 +249,129 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
228 | 249 | ||
229 | // Each iteration is really a separate asset being created, | 250 | // Each iteration is really a separate asset being created, |
230 | // with distinct destinations as well. | 251 | // with distinct destinations as well. |
231 | foreach (List<SceneObjectGroup> objlist in deletes.Values) | 252 | foreach (List<SceneObjectGroup> bundle in bundlesToCopy.Values) |
253 | assetID = CopyBundleToInventory(action, folderID, bundle, remoteClient); | ||
254 | |||
255 | return assetID; | ||
256 | } | ||
257 | |||
258 | /// <summary> | ||
259 | /// Copy a bundle of objects to inventory. If there is only one object, then this will create an object | ||
260 | /// item. If there are multiple objects then these will be saved as a single coalesced item. | ||
261 | /// </summary> | ||
262 | /// <param name="action"></param> | ||
263 | /// <param name="folderID"></param> | ||
264 | /// <param name="objlist"></param> | ||
265 | /// <param name="remoteClient"></param> | ||
266 | /// <returns></returns> | ||
267 | protected UUID CopyBundleToInventory( | ||
268 | DeRezAction action, UUID folderID, List<SceneObjectGroup> objlist, IClientAPI remoteClient) | ||
269 | { | ||
270 | UUID assetID = UUID.Zero; | ||
271 | |||
272 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); | ||
273 | Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); | ||
274 | |||
275 | foreach (SceneObjectGroup objectGroup in objlist) | ||
232 | { | 276 | { |
233 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); | 277 | Vector3 inventoryStoredPosition = new Vector3 |
234 | Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); | 278 | (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) |
279 | ? 250 | ||
280 | : objectGroup.AbsolutePosition.X) | ||
281 | , | ||
282 | (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) | ||
283 | ? 250 | ||
284 | : objectGroup.AbsolutePosition.Y, | ||
285 | objectGroup.AbsolutePosition.Z); | ||
286 | |||
287 | originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; | ||
288 | |||
289 | objectGroup.AbsolutePosition = inventoryStoredPosition; | ||
290 | |||
291 | // Make sure all bits but the ones we want are clear | ||
292 | // on take. | ||
293 | // This will be applied to the current perms, so | ||
294 | // it will do what we want. | ||
295 | objectGroup.RootPart.NextOwnerMask &= | ||
296 | ((uint)PermissionMask.Copy | | ||
297 | (uint)PermissionMask.Transfer | | ||
298 | (uint)PermissionMask.Modify); | ||
299 | objectGroup.RootPart.NextOwnerMask |= | ||
300 | (uint)PermissionMask.Move; | ||
301 | |||
302 | coa.Add(objectGroup); | ||
303 | } | ||
235 | 304 | ||
236 | foreach (SceneObjectGroup objectGroup in objlist) | 305 | string itemXml; |
237 | { | ||
238 | Vector3 inventoryStoredPosition = new Vector3 | ||
239 | (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) | ||
240 | ? 250 | ||
241 | : objectGroup.AbsolutePosition.X) | ||
242 | , | ||
243 | (objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) | ||
244 | ? 250 | ||
245 | : objectGroup.AbsolutePosition.X, | ||
246 | objectGroup.AbsolutePosition.Z); | ||
247 | |||
248 | originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; | ||
249 | |||
250 | objectGroup.AbsolutePosition = inventoryStoredPosition; | ||
251 | |||
252 | // Make sure all bits but the ones we want are clear | ||
253 | // on take. | ||
254 | // This will be applied to the current perms, so | ||
255 | // it will do what we want. | ||
256 | objectGroup.RootPart.NextOwnerMask &= | ||
257 | ((uint)PermissionMask.Copy | | ||
258 | (uint)PermissionMask.Transfer | | ||
259 | (uint)PermissionMask.Modify); | ||
260 | objectGroup.RootPart.NextOwnerMask |= | ||
261 | (uint)PermissionMask.Move; | ||
262 | |||
263 | coa.Add(objectGroup); | ||
264 | } | ||
265 | 306 | ||
266 | string itemXml; | 307 | if (objlist.Count > 1) |
308 | itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); | ||
309 | else | ||
310 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); | ||
311 | |||
312 | // Restore the position of each group now that it has been stored to inventory. | ||
313 | foreach (SceneObjectGroup objectGroup in objlist) | ||
314 | objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; | ||
267 | 315 | ||
268 | if (objlist.Count > 1) | 316 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); |
269 | itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); | 317 | if (item == null) |
270 | else | 318 | return UUID.Zero; |
271 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); | 319 | |
272 | 320 | // Can't know creator is the same, so null it in inventory | |
273 | // Restore the position of each group now that it has been stored to inventory. | 321 | if (objlist.Count > 1) |
274 | foreach (SceneObjectGroup objectGroup in objlist) | 322 | { |
275 | objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; | 323 | item.CreatorId = UUID.Zero.ToString(); |
324 | item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; | ||
325 | } | ||
326 | else | ||
327 | { | ||
328 | item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); | ||
329 | item.SaleType = objlist[0].RootPart.ObjectSaleType; | ||
330 | item.SalePrice = objlist[0].RootPart.SalePrice; | ||
331 | } | ||
332 | |||
333 | AssetBase asset = CreateAsset( | ||
334 | objlist[0].GetPartName(objlist[0].RootPart.LocalId), | ||
335 | objlist[0].GetPartDescription(objlist[0].RootPart.LocalId), | ||
336 | (sbyte)AssetType.Object, | ||
337 | Utils.StringToBytes(itemXml), | ||
338 | objlist[0].OwnerID.ToString()); | ||
339 | m_Scene.AssetService.Store(asset); | ||
340 | |||
341 | item.AssetID = asset.FullID; | ||
342 | assetID = asset.FullID; | ||
276 | 343 | ||
277 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); | 344 | if (DeRezAction.SaveToExistingUserInventoryItem == action) |
278 | if (item == null) | 345 | { |
279 | return UUID.Zero; | 346 | m_Scene.InventoryService.UpdateItem(item); |
280 | 347 | } | |
281 | // Can't know creator is the same, so null it in inventory | 348 | else |
282 | if (objlist.Count > 1) | 349 | { |
283 | { | 350 | AddPermissions(item, objlist[0], objlist, remoteClient); |
284 | item.CreatorId = UUID.Zero.ToString(); | 351 | |
285 | item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; | 352 | item.CreationDate = Util.UnixTimeSinceEpoch(); |
286 | } | 353 | item.Description = asset.Description; |
287 | else | 354 | item.Name = asset.Name; |
288 | { | 355 | item.AssetType = asset.Type; |
289 | item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); | 356 | |
290 | item.SaleType = objlist[0].RootPart.ObjectSaleType; | 357 | m_Scene.AddInventoryItem(item); |
291 | item.SalePrice = objlist[0].RootPart.SalePrice; | ||
292 | } | ||
293 | |||
294 | AssetBase asset = CreateAsset( | ||
295 | objlist[0].GetPartName(objlist[0].RootPart.LocalId), | ||
296 | objlist[0].GetPartDescription(objlist[0].RootPart.LocalId), | ||
297 | (sbyte)AssetType.Object, | ||
298 | Utils.StringToBytes(itemXml), | ||
299 | objlist[0].OwnerID.ToString()); | ||
300 | m_Scene.AssetService.Store(asset); | ||
301 | |||
302 | item.AssetID = asset.FullID; | ||
303 | assetID = asset.FullID; | ||
304 | 358 | ||
305 | if (DeRezAction.SaveToExistingUserInventoryItem == action) | 359 | if (remoteClient != null && item.Owner == remoteClient.AgentId) |
306 | { | 360 | { |
307 | m_Scene.InventoryService.UpdateItem(item); | 361 | remoteClient.SendInventoryItemCreateUpdate(item, 0); |
308 | } | 362 | } |
309 | else | 363 | else |
310 | { | 364 | { |
311 | AddPermissions(item, objlist[0], objlist, remoteClient); | 365 | ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner); |
312 | 366 | if (notifyUser != null) | |
313 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
314 | item.Description = asset.Description; | ||
315 | item.Name = asset.Name; | ||
316 | item.AssetType = asset.Type; | ||
317 | |||
318 | m_Scene.AddInventoryItem(item); | ||
319 | |||
320 | if (remoteClient != null && item.Owner == remoteClient.AgentId) | ||
321 | { | ||
322 | remoteClient.SendInventoryItemCreateUpdate(item, 0); | ||
323 | } | ||
324 | else | ||
325 | { | 367 | { |
326 | ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner); | 368 | notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); |
327 | if (notifyUser != null) | ||
328 | { | ||
329 | notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); | ||
330 | } | ||
331 | } | 369 | } |
332 | } | 370 | } |
333 | |||
334 | // This is a hook to do some per-asset post-processing for subclasses that need that | ||
335 | ExportAsset(remoteClient.AgentId, assetID); | ||
336 | } | 371 | } |
372 | |||
373 | // This is a hook to do some per-asset post-processing for subclasses that need that | ||
374 | ExportAsset(remoteClient.AgentId, assetID); | ||
337 | 375 | ||
338 | return assetID; | 376 | return assetID; |
339 | } | 377 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index fd8f546..82bef48 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | |||
@@ -57,6 +57,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
57 | /// bumps here should be compatible. | 57 | /// bumps here should be compatible. |
58 | /// </summary> | 58 | /// </summary> |
59 | public static int MAX_MAJOR_VERSION = 1; | 59 | public static int MAX_MAJOR_VERSION = 1; |
60 | |||
61 | /// <summary> | ||
62 | /// Has the control file been loaded for this archive? | ||
63 | /// </summary> | ||
64 | public bool ControlFileLoaded { get; private set; } | ||
60 | 65 | ||
61 | protected Scene m_scene; | 66 | protected Scene m_scene; |
62 | protected Stream m_loadStream; | 67 | protected Stream m_loadStream; |
@@ -527,7 +532,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
527 | /// </summary> | 532 | /// </summary> |
528 | /// <param name="path"></param> | 533 | /// <param name="path"></param> |
529 | /// <param name="data"></param> | 534 | /// <param name="data"></param> |
530 | protected void LoadControlFile(string path, byte[] data) | 535 | public void LoadControlFile(string path, byte[] data) |
531 | { | 536 | { |
532 | XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); | 537 | XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); |
533 | XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); | 538 | XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); |
@@ -573,6 +578,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
573 | } | 578 | } |
574 | 579 | ||
575 | currentRegionSettings.Save(); | 580 | currentRegionSettings.Save(); |
581 | |||
582 | ControlFileLoaded = true; | ||
576 | } | 583 | } |
577 | } | 584 | } |
578 | } \ No newline at end of file | 585 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs index f2d487e..597b780 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs | |||
@@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
206 | /// <returns></returns> | 206 | /// <returns></returns> |
207 | public static string CreateControlFile(Dictionary<string, object> options) | 207 | public static string CreateControlFile(Dictionary<string, object> options) |
208 | { | 208 | { |
209 | int majorVersion = MAX_MAJOR_VERSION, minorVersion = 5; | 209 | int majorVersion = MAX_MAJOR_VERSION, minorVersion = 6; |
210 | // | 210 | // |
211 | // if (options.ContainsKey("version")) | 211 | // if (options.ContainsKey("version")) |
212 | // { | 212 | // { |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index e2760a2..2307c8e 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs | |||
@@ -171,7 +171,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
171 | MemoryStream archiveReadStream = new MemoryStream(archive); | 171 | MemoryStream archiveReadStream = new MemoryStream(archive); |
172 | TarArchiveReader tar = new TarArchiveReader(archiveReadStream); | 172 | TarArchiveReader tar = new TarArchiveReader(archiveReadStream); |
173 | 173 | ||
174 | bool gotControlFile = false; | ||
175 | bool gotNcAssetFile = false; | 174 | bool gotNcAssetFile = false; |
176 | 175 | ||
177 | string expectedNcAssetFileName = string.Format("{0}_{1}", ncAssetUuid, "notecard.txt"); | 176 | string expectedNcAssetFileName = string.Format("{0}_{1}", ncAssetUuid, "notecard.txt"); |
@@ -182,15 +181,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
182 | expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); | 181 | expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); |
183 | 182 | ||
184 | string filePath; | 183 | string filePath; |
185 | TarArchiveReader.TarEntryType tarEntryType; | 184 | TarArchiveReader.TarEntryType tarEntryType; |
186 | 185 | ||
186 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | ||
187 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | ||
188 | |||
189 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | ||
190 | arr.LoadControlFile(filePath, data); | ||
191 | |||
192 | Assert.That(arr.ControlFileLoaded, Is.True); | ||
193 | |||
187 | while (tar.ReadEntry(out filePath, out tarEntryType) != null) | 194 | while (tar.ReadEntry(out filePath, out tarEntryType) != null) |
188 | { | 195 | { |
189 | if (ArchiveConstants.CONTROL_FILE_PATH == filePath) | 196 | if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) |
190 | { | ||
191 | gotControlFile = true; | ||
192 | } | ||
193 | else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) | ||
194 | { | 197 | { |
195 | string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); | 198 | string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); |
196 | 199 | ||
@@ -203,7 +206,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
203 | } | 206 | } |
204 | } | 207 | } |
205 | 208 | ||
206 | Assert.That(gotControlFile, Is.True, "No control file in archive"); | ||
207 | Assert.That(gotNcAssetFile, Is.True, "No notecard asset file in archive"); | 209 | Assert.That(gotNcAssetFile, Is.True, "No notecard asset file in archive"); |
208 | Assert.That(foundPaths, Is.EquivalentTo(expectedPaths)); | 210 | Assert.That(foundPaths, Is.EquivalentTo(expectedPaths)); |
209 | 211 | ||
diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 05fc2ad..305975e 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs | |||
@@ -38,7 +38,23 @@ namespace OpenSim.Region.Framework.Interfaces | |||
38 | public interface IInventoryAccessModule | 38 | public interface IInventoryAccessModule |
39 | { | 39 | { |
40 | UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data); | 40 | UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data); |
41 | UUID DeleteToInventory(DeRezAction action, UUID folderID, List<SceneObjectGroup> objectGroups, IClientAPI remoteClient); | 41 | |
42 | /// <summary> | ||
43 | /// Copy objects to a user's inventory. | ||
44 | /// </summary> | ||
45 | /// <remarks> | ||
46 | /// Is it left to the caller to delete them from the scene if required. | ||
47 | /// </remarks> | ||
48 | /// <param name="action"></param> | ||
49 | /// <param name="folderID"></param> | ||
50 | /// <param name="objectGroups"></param> | ||
51 | /// <param name="remoteClient"></param> | ||
52 | /// <returns> | ||
53 | /// Returns the UUID of the newly created item asset (not the item itself). | ||
54 | /// FIXME: This is not very useful. It would be far more useful to return a list of items instead. | ||
55 | /// </returns> | ||
56 | UUID CopyToInventory(DeRezAction action, UUID folderID, List<SceneObjectGroup> objectGroups, IClientAPI remoteClient); | ||
57 | |||
42 | SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, | 58 | SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, |
43 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | 59 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, |
44 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); | 60 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); |
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index 8feb022..3423542 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs | |||
@@ -143,7 +143,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
143 | { | 143 | { |
144 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 144 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); |
145 | if (invAccess != null) | 145 | if (invAccess != null) |
146 | invAccess.DeleteToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); | 146 | invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); |
147 | |||
147 | if (x.permissionToDelete) | 148 | if (x.permissionToDelete) |
148 | { | 149 | { |
149 | foreach (SceneObjectGroup g in x.objectGroups) | 150 | foreach (SceneObjectGroup g in x.objectGroups) |
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 107e859..e72e851 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini | |||
@@ -155,10 +155,6 @@ | |||
155 | ; it may cause unexpected physics problems. | 155 | ; it may cause unexpected physics problems. |
156 | ;UseMeshiesPhysicsMesh = false | 156 | ;UseMeshiesPhysicsMesh = false |
157 | 157 | ||
158 | ; enable / disable Collada mesh support | ||
159 | ; default is true | ||
160 | ; ColladaMesh = true | ||
161 | |||
162 | ; Choose one of the physics engines below | 158 | ; Choose one of the physics engines below |
163 | ; OpenDynamicsEngine is by some distance the most developed physics engine | 159 | ; OpenDynamicsEngine is by some distance the most developed physics engine |
164 | ; basicphysics effectively does not model physics at all, making all objects phantom | 160 | ; basicphysics effectively does not model physics at all, making all objects phantom |
@@ -453,6 +449,19 @@ | |||
453 | ; ForwardOfflineGroupMessages = true | 449 | ; ForwardOfflineGroupMessages = true |
454 | 450 | ||
455 | 451 | ||
452 | [Inventory] | ||
453 | ; Control whether multiple objects sent to inventory should be coaleseced into a single item | ||
454 | ; There are still some issues with coalescence, including the fact that rotation is not restored | ||
455 | ; and some assets may be missing from archive files. | ||
456 | CoalesceMultipleObjectsToInventory = true | ||
457 | |||
458 | |||
459 | [Mesh] | ||
460 | ; enable / disable Collada mesh support | ||
461 | ; default is true | ||
462 | ; ColladaMesh = true | ||
463 | |||
464 | |||
456 | [ODEPhysicsSettings] | 465 | [ODEPhysicsSettings] |
457 | ;## | 466 | ;## |
458 | ;## World Settings | 467 | ;## World Settings |