aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs713
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs79
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs5
3 files changed, 547 insertions, 250 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 05a2a63..630b6e6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -51,6 +51,44 @@ using Nini.Config;
51 51
52namespace OpenSim.Region.ClientStack.LindenUDP 52namespace OpenSim.Region.ClientStack.LindenUDP
53{ 53{
54 #region Enums
55
56 /// <summary>
57 /// Specifies the fields that have been changed when sending a prim or
58 /// avatar update
59 /// </summary>
60 [Flags]
61 public enum PrimUpdateFlags : uint
62 {
63 None = 0,
64 AttachmentPoint = 1 << 0,
65 Material = 1 << 1,
66 ClickAction = 1 << 2,
67 Scale = 1 << 3,
68 ParentID = 1 << 4,
69 PrimFlags = 1 << 5,
70 PrimData = 1 << 6,
71 MediaURL = 1 << 7,
72 ScratchPad = 1 << 8,
73 Textures = 1 << 9,
74 TextureAnim = 1 << 10,
75 NameValue = 1 << 11,
76 Position = 1 << 12,
77 Rotation = 1 << 13,
78 Velocity = 1 << 14,
79 Acceleration = 1 << 15,
80 AngularVelocity = 1 << 16,
81 CollisionPlane = 1 << 17,
82 Text = 1 << 18,
83 Particles = 1 << 19,
84 ExtraData = 1 << 20,
85 Sound = 1 << 21,
86 Joint = 1 << 22,
87 FullUpdate = UInt32.MaxValue
88 }
89
90 #endregion Enums
91
54 public delegate bool PacketMethod(IClientAPI simClient, Packet packet); 92 public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
55 93
56 /// <summary> 94 /// <summary>
@@ -282,12 +320,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
282 private readonly IGroupsModule m_GroupsModule; 320 private readonly IGroupsModule m_GroupsModule;
283 321
284 private int m_cachedTextureSerial; 322 private int m_cachedTextureSerial;
285 private Timer m_avatarTerseUpdateTimer; 323 private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates =
286 private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); 324 new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
287 private Timer m_primTerseUpdateTimer; 325 private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates =
288 private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); 326 new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
289 private Timer m_primFullUpdateTimer; 327 private PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates =
290 private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates = new List<ObjectUpdatePacket.ObjectDataBlock>(); 328 new PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>();
291 private int m_moneyBalance; 329 private int m_moneyBalance;
292 private int m_animationSequenceNumber = 1; 330 private int m_animationSequenceNumber = 1;
293 private bool m_SendLogoutPacketWhenClosing = true; 331 private bool m_SendLogoutPacketWhenClosing = true;
@@ -312,9 +350,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
312 // LL uses these limits, apparently. Compressed terse would be 23, but we don't have that yet 350 // LL uses these limits, apparently. Compressed terse would be 23, but we don't have that yet
313 protected int m_primTerseUpdatesPerPacket = 10; 351 protected int m_primTerseUpdatesPerPacket = 10;
314 protected int m_primFullUpdatesPerPacket = 14; 352 protected int m_primFullUpdatesPerPacket = 14;
315 protected int m_primTerseUpdateRate = 10;
316 protected int m_primFullUpdateRate = 14;
317 protected int m_avatarTerseUpdateRate = 50;
318 protected int m_avatarTerseUpdatesPerPacket = 5; 353 protected int m_avatarTerseUpdatesPerPacket = 5;
319 /// <summary>Number of texture packets to put on the queue each time the 354 /// <summary>Number of texture packets to put on the queue each time the
320 /// OnQueueEmpty event is triggered for the texture category</summary> 355 /// OnQueueEmpty event is triggered for the texture category</summary>
@@ -438,25 +473,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
438 // Remove ourselves from the scene 473 // Remove ourselves from the scene
439 m_scene.RemoveClient(AgentId); 474 m_scene.RemoveClient(AgentId);
440 475
441 // Shut down timers. Thread Context of this method is murky. Lock all timers
442 if (m_avatarTerseUpdateTimer.Enabled)
443 lock (m_avatarTerseUpdateTimer)
444 m_avatarTerseUpdateTimer.Stop();
445 if (m_primTerseUpdateTimer.Enabled)
446 lock (m_primTerseUpdateTimer)
447 m_primTerseUpdateTimer.Stop();
448 if (m_primFullUpdateTimer.Enabled)
449 lock (m_primFullUpdateTimer)
450 m_primFullUpdateTimer.Stop();
451
452 // We can't reach into other scenes and close the connection 476 // We can't reach into other scenes and close the connection
453 // We need to do this over grid communications 477 // We need to do this over grid communications
454 //m_scene.CloseAllAgents(CircuitCode); 478 //m_scene.CloseAllAgents(CircuitCode);
455 479
456 m_avatarTerseUpdateTimer.Dispose();
457 m_primTerseUpdateTimer.Dispose();
458 m_primFullUpdateTimer.Dispose();
459
460 // Disable UDP handling for this client 480 // Disable UDP handling for this client
461 m_udpClient.Shutdown(); 481 m_udpClient.Shutdown();
462 482
@@ -483,18 +503,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
483 503
484 public void Stop() 504 public void Stop()
485 { 505 {
486 // Shut down timers. Thread Context is Murky, lock all timers!
487 if (m_avatarTerseUpdateTimer.Enabled)
488 lock (m_avatarTerseUpdateTimer)
489 m_avatarTerseUpdateTimer.Stop();
490 506
491 if (m_primTerseUpdateTimer.Enabled)
492 lock (m_primTerseUpdateTimer)
493 m_primTerseUpdateTimer.Stop();
494
495 if (m_primFullUpdateTimer.Enabled)
496 lock (m_primFullUpdateTimer)
497 m_primFullUpdateTimer.Stop();
498 } 507 }
499 508
500 #endregion Client Methods 509 #endregion Client Methods
@@ -590,18 +599,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
590 599
591 public virtual void Start() 600 public virtual void Start()
592 { 601 {
593 m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate);
594 m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates);
595 m_avatarTerseUpdateTimer.AutoReset = false;
596
597 m_primTerseUpdateTimer = new Timer(m_primTerseUpdateRate);
598 m_primTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimTerseUpdates);
599 m_primTerseUpdateTimer.AutoReset = false;
600
601 m_primFullUpdateTimer = new Timer(m_primFullUpdateRate);
602 m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates);
603 m_primFullUpdateTimer.AutoReset = false;
604
605 m_scene.AddNewClient(this); 602 m_scene.AddNewClient(this);
606 603
607 RefreshGroupMembership(); 604 RefreshGroupMembership();
@@ -3127,7 +3124,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3127 3124
3128 avp.Sender.IsTrial = false; 3125 avp.Sender.IsTrial = false;
3129 avp.Sender.ID = agentID; 3126 avp.Sender.ID = agentID;
3130 OutPacket(avp, ThrottleOutPacketType.State); 3127 OutPacket(avp, ThrottleOutPacketType.Task);
3131 } 3128 }
3132 3129
3133 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) 3130 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
@@ -3159,33 +3156,221 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3159 3156
3160 #endregion 3157 #endregion
3161 3158
3159 #region Prim/Avatar Updates
3160
3161 /*void SendObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags)
3162 {
3163 bool canUseCompressed, canUseImproved;
3164 UpdateFlagsToPacketType(creatorFlags, updateFlags, out canUseCompressed, out canUseImproved);
3165
3166 if (!canUseImproved && !canUseCompressed)
3167 SendFullObjectUpdate(obj, creatorFlags, updateFlags);
3168 else if (!canUseImproved)
3169 SendObjectUpdateCompressed(obj, creatorFlags, updateFlags);
3170 else
3171 SendImprovedTerseObjectUpdate(obj, creatorFlags, updateFlags);
3172 }
3173
3174 void SendFullObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags)
3175 {
3176 IClientAPI owner;
3177 if (m_scene.ClientManager.TryGetValue(obj.OwnerID, out owner) && owner is LLClientView)
3178 {
3179 LLClientView llOwner = (LLClientView)owner;
3180
3181 // Send an update out to the owner
3182 ObjectUpdatePacket updateToOwner = new ObjectUpdatePacket();
3183 updateToOwner.RegionData.RegionHandle = obj.RegionHandle;
3184 //updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue);
3185 updateToOwner.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3186 updateToOwner.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags | creatorFlags | PrimFlags.ObjectYouOwner, 0);
3187
3188 m_udpServer.SendPacket(llOwner.UDPClient, updateToOwner, ThrottleOutPacketType.State, true);
3189 }
3190
3191 // Send an update out to everyone else
3192 ObjectUpdatePacket updateToOthers = new ObjectUpdatePacket();
3193 updateToOthers.RegionData.RegionHandle = obj.RegionHandle;
3194 //updateToOthers.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue);
3195 updateToOthers.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3196 updateToOthers.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags, 0);
3197
3198 m_scene.ClientManager.ForEach(
3199 delegate(IClientAPI client)
3200 {
3201 if (client.AgentId != obj.OwnerID && client is LLClientView)
3202 {
3203 LLClientView llClient = (LLClientView)client;
3204 m_udpServer.SendPacket(llClient.UDPClient, updateToOthers, ThrottleOutPacketType.State, true);
3205 }
3206 }
3207 );
3208 }
3209
3210 void SendObjectUpdateCompressed(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags)
3211 {
3212 }
3213
3214 void SendImprovedTerseObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags)
3215 {
3216 }
3217
3218 void UpdateFlagsToPacketType(PrimFlags creatorFlags, PrimUpdateFlags updateFlags, out bool canUseCompressed, out bool canUseImproved)
3219 {
3220 canUseCompressed = true;
3221 canUseImproved = true;
3222
3223 if ((updateFlags & PrimUpdateFlags.FullUpdate) == PrimUpdateFlags.FullUpdate || creatorFlags != PrimFlags.None)
3224 {
3225 canUseCompressed = false;
3226 canUseImproved = false;
3227 }
3228 else
3229 {
3230 if ((updateFlags & PrimUpdateFlags.Velocity) != 0 ||
3231 (updateFlags & PrimUpdateFlags.Acceleration) != 0 ||
3232 (updateFlags & PrimUpdateFlags.CollisionPlane) != 0 ||
3233 (updateFlags & PrimUpdateFlags.Joint) != 0)
3234 {
3235 canUseCompressed = false;
3236 }
3237
3238 if ((updateFlags & PrimUpdateFlags.PrimFlags) != 0 ||
3239 (updateFlags & PrimUpdateFlags.ParentID) != 0 ||
3240 (updateFlags & PrimUpdateFlags.Scale) != 0 ||
3241 (updateFlags & PrimUpdateFlags.PrimData) != 0 ||
3242 (updateFlags & PrimUpdateFlags.Text) != 0 ||
3243 (updateFlags & PrimUpdateFlags.NameValue) != 0 ||
3244 (updateFlags & PrimUpdateFlags.ExtraData) != 0 ||
3245 (updateFlags & PrimUpdateFlags.TextureAnim) != 0 ||
3246 (updateFlags & PrimUpdateFlags.Sound) != 0 ||
3247 (updateFlags & PrimUpdateFlags.Particles) != 0 ||
3248 (updateFlags & PrimUpdateFlags.Material) != 0 ||
3249 (updateFlags & PrimUpdateFlags.ClickAction) != 0 ||
3250 (updateFlags & PrimUpdateFlags.MediaURL) != 0 ||
3251 (updateFlags & PrimUpdateFlags.Joint) != 0)
3252 {
3253 canUseImproved = false;
3254 }
3255 }
3256 }
3257
3258 static ObjectUpdatePacket.ObjectDataBlock BuildUpdateBlockFromPrim(SceneObjectPart prim, UUID assetID, PrimFlags flags, uint crc)
3259 {
3260 byte[] objectData = new byte[60];
3261 prim.OffsetPosition.ToBytes(objectData, 0);
3262 prim.Velocity.ToBytes(objectData, 12);
3263 prim.Acceleration.ToBytes(objectData, 24);
3264 prim.RotationOffset.ToBytes(objectData, 36);
3265 prim.AngularVelocity.ToBytes(objectData, 48);
3266
3267 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
3268 update.ClickAction = (byte)prim.ClickAction;
3269 update.CRC = crc;
3270 update.ExtraParams = prim.Shape.ExtraParams ?? Utils.EmptyBytes;
3271 update.Flags = (byte)flags;
3272 update.FullID = prim.UUID;
3273 update.ID = prim.LocalId;
3274 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated
3275 //update.JointPivot = Vector3.Zero;
3276 //update.JointType = 0;
3277 update.Material = prim.Material;
3278 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
3279 if (prim.IsAttachment)
3280 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + assetID);
3281 else
3282 update.NameValue = Utils.EmptyBytes;
3283 update.ObjectData = objectData;
3284 update.ParentID = prim.ParentID;
3285 update.PathBegin = prim.Shape.PathBegin;
3286 update.PathCurve = prim.Shape.PathCurve;
3287 update.PathEnd = prim.Shape.PathEnd;
3288 update.PathRadiusOffset = prim.Shape.PathRadiusOffset;
3289 update.PathRevolutions = prim.Shape.PathRevolutions;
3290 update.PathScaleX = prim.Shape.PathScaleX;
3291 update.PathScaleY = prim.Shape.PathScaleY;
3292 update.PathShearX = prim.Shape.PathShearX;
3293 update.PathShearY = prim.Shape.PathShearY;
3294 update.PathSkew = prim.Shape.PathSkew;
3295 update.PathTaperX = prim.Shape.PathTaperX;
3296 update.PathTaperY = prim.Shape.PathTaperY;
3297 update.PathTwist = prim.Shape.PathTwist;
3298 update.PathTwistBegin = prim.Shape.PathTwistBegin;
3299 update.PCode = prim.Shape.PCode;
3300 update.ProfileBegin = prim.Shape.ProfileBegin;
3301 update.ProfileCurve = prim.Shape.ProfileCurve;
3302 update.ProfileEnd = prim.Shape.ProfileEnd;
3303 update.ProfileHollow = prim.Shape.ProfileHollow;
3304 update.PSBlock = prim.ParticleSystem ?? Utils.EmptyBytes;
3305 update.TextColor = new Color4(prim.Color).GetBytes(true);
3306 update.TextureAnim = prim.TextureAnimation ?? Utils.EmptyBytes;
3307 update.TextureEntry = prim.Shape.TextureEntry ?? Utils.EmptyBytes;
3308 update.Scale = prim.Scale;
3309 update.State = prim.Shape.State;
3310 update.Text = Util.StringToBytes256(prim.Text);
3311 update.UpdateFlags = (uint)flags;
3312
3313 if (prim.Sound != UUID.Zero)
3314 {
3315 update.Sound = prim.Sound;
3316 update.OwnerID = prim.OwnerID;
3317 update.Gain = (float)prim.SoundGain;
3318 update.Radius = (float)prim.SoundRadius;
3319 }
3320
3321 switch ((PCode)prim.Shape.PCode)
3322 {
3323 case PCode.Grass:
3324 case PCode.Tree:
3325 case PCode.NewTree:
3326 update.Data = new byte[] { prim.Shape.State };
3327 break;
3328 default:
3329 // TODO: Support ScratchPad
3330 //if (prim.ScratchPad != null)
3331 //{
3332 // update.Data = new byte[prim.ScratchPad.Length];
3333 // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length);
3334 //}
3335 //else
3336 //{
3337 // update.Data = Utils.EmptyBytes;
3338 //}
3339 update.Data = Utils.EmptyBytes;
3340 break;
3341 }
3342
3343 return update;
3344 }*/
3345
3346 #endregion Prim/Avatar Updates
3347
3162 #region Avatar Packet/data sending Methods 3348 #region Avatar Packet/data sending Methods
3163 3349
3164 /// <summary> 3350 /// <summary>
3165 /// send a objectupdate packet with information about the clients avatar 3351 /// send a objectupdate packet with information about the clients avatar
3166 /// </summary> 3352 /// </summary>
3167 public void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, 3353 public void SendAvatarData(SendAvatarData data)
3168 uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation)
3169 { 3354 {
3170 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3355 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3171 // TODO: don't create new blocks if recycling an old packet 3356 // TODO: don't create new blocks if recycling an old packet
3172 objupdate.RegionData.RegionHandle = regionHandle; 3357 objupdate.RegionData.RegionHandle = data.regionHandle;
3173 objupdate.RegionData.TimeDilation = ushort.MaxValue; 3358 objupdate.RegionData.TimeDilation = ushort.MaxValue;
3174 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; 3359 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3175 objupdate.ObjectData[0] = CreateDefaultAvatarPacket(textureEntry); 3360 objupdate.ObjectData[0] = CreateDefaultAvatarPacket(data.textureEntry);
3176 3361
3177 //give this avatar object a local id and assign the user a name 3362 //give this avatar object a local id and assign the user a name
3178 objupdate.ObjectData[0].ID = avatarLocalID; 3363 objupdate.ObjectData[0].ID = data.avatarLocalID;
3179 objupdate.ObjectData[0].FullID = avatarID; 3364 objupdate.ObjectData[0].FullID = data.avatarID;
3180 objupdate.ObjectData[0].ParentID = parentID; 3365 objupdate.ObjectData[0].ParentID = data.parentID;
3181 objupdate.ObjectData[0].NameValue = 3366 objupdate.ObjectData[0].NameValue =
3182 Utils.StringToBytes("FirstName STRING RW SV " + firstName + "\nLastName STRING RW SV " + lastName + "\nTitle STRING RW SV " + grouptitle); 3367 Utils.StringToBytes("FirstName STRING RW SV " + data.firstName + "\nLastName STRING RW SV " + data.lastName + "\nTitle STRING RW SV " + data.grouptitle);
3183 3368
3184 Vector3 pos2 = new Vector3(Pos.X, Pos.Y, Pos.Z); 3369 Vector3 pos2 = new Vector3(data.Pos.X, data.Pos.Y, data.Pos.Z);
3185 byte[] pb = pos2.GetBytes(); 3370 byte[] pb = pos2.GetBytes();
3186 Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); 3371 Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length);
3187 3372
3188 byte[] rot = rotation.GetBytes(); 3373 byte[] rot = data.rotation.GetBytes();
3189 Array.Copy(rot, 0, objupdate.ObjectData[0].ObjectData, 52, rot.Length); 3374 Array.Copy(rot, 0, objupdate.ObjectData[0].ObjectData, 52, rot.Length);
3190 3375
3191 objupdate.Header.Zerocoded = true; 3376 objupdate.Header.Zerocoded = true;
@@ -3196,38 +3381,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3196 /// Send a terse positional/rotation/velocity update about an avatar 3381 /// Send a terse positional/rotation/velocity update about an avatar
3197 /// to the client. This avatar can be that of the client itself. 3382 /// to the client. This avatar can be that of the client itself.
3198 /// </summary> 3383 /// </summary>
3199 public virtual void SendAvatarTerseUpdate(ulong regionHandle, 3384 public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data)
3200 ushort timeDilation, uint localID, Vector3 position,
3201 Vector3 velocity, Quaternion rotation, UUID agentid)
3202 { 3385 {
3386 if (data.priority == double.NaN)
3387 {
3388 m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update");
3389 return;
3390 }
3391
3392 Quaternion rotation = data.rotation;
3393
3203 if (rotation.X == rotation.Y && 3394 if (rotation.X == rotation.Y &&
3204 rotation.Y == rotation.Z && 3395 rotation.Y == rotation.Z &&
3205 rotation.Z == rotation.W && rotation.W == 0) 3396 rotation.Z == rotation.W && rotation.W == 0)
3206 rotation = Quaternion.Identity; 3397 rotation = Quaternion.Identity;
3207 3398
3208 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = 3399 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock =
3209 CreateAvatarImprovedBlock(localID, position, velocity,rotation); 3400 CreateAvatarImprovedBlock(data.localID, data.position, data.velocity, rotation);
3210 3401
3211 lock (m_avatarTerseUpdates) 3402 lock (m_avatarTerseUpdates.SyncRoot)
3212 { 3403 m_avatarTerseUpdates.Enqueue(data.priority, terseBlock, data.localID);
3213 m_avatarTerseUpdates.Add(terseBlock);
3214
3215 // If packet is full or own movement packet, send it.
3216 if (m_avatarTerseUpdates.Count >= m_avatarTerseUpdatesPerPacket)
3217 {
3218 ProcessAvatarTerseUpdates(this, null);
3219 }
3220 else if (m_avatarTerseUpdates.Count == 1)
3221 {
3222 lock (m_avatarTerseUpdateTimer)
3223 m_avatarTerseUpdateTimer.Start();
3224 }
3225 }
3226 } 3404 }
3227 3405
3228 private void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) 3406 private void ProcessAvatarTerseUpdates()
3229 { 3407 {
3230 lock (m_avatarTerseUpdates) 3408 lock (m_avatarTerseUpdates.SyncRoot)
3231 { 3409 {
3232 ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 3410 ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3233 3411
@@ -3247,34 +3425,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3247 byte[] zerobuffer = new byte[1024]; 3425 byte[] zerobuffer = new byte[1024];
3248 byte[] blockbuffer = new byte[1024]; 3426 byte[] blockbuffer = new byte[1024];
3249 3427
3428 Queue<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> updates = new Queue<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
3429
3250 for (count = 0 ; count < max ; count++) 3430 for (count = 0 ; count < max ; count++)
3251 { 3431 {
3252 int length = 0; 3432 int length = 0;
3253 m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); 3433 m_avatarTerseUpdates.Peek().ToBytes(blockbuffer, ref length);
3254 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); 3434 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer);
3255 if (size + length > Packet.MTU) 3435 if (size + length > Packet.MTU)
3256 break; 3436 break;
3257 size += length; 3437 size += length;
3438 updates.Enqueue(m_avatarTerseUpdates.Dequeue());
3258 } 3439 }
3259 3440
3260 terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; 3441 terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count];
3261 3442
3262 for (int i = 0 ; i < count ; i++) 3443 for (int i = 0 ; i < count ; i++)
3263 { 3444 terse.ObjectData[i] = updates.Dequeue();
3264 terse.ObjectData[i] = m_avatarTerseUpdates[0];
3265 m_avatarTerseUpdates.RemoveAt(0);
3266 }
3267 3445
3268 terse.Header.Reliable = false; 3446 terse.Header.Reliable = false;
3269 terse.Header.Zerocoded = true; 3447 terse.Header.Zerocoded = true;
3270 // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed
3271 OutPacket(terse, ThrottleOutPacketType.Task);
3272 3448
3273 if (m_avatarTerseUpdates.Count == 0) 3449 OutPacket(terse, ThrottleOutPacketType.State);
3274 {
3275 lock (m_avatarTerseUpdateTimer)
3276 m_avatarTerseUpdateTimer.Stop();
3277 }
3278 } 3450 }
3279 } 3451 }
3280 3452
@@ -3342,54 +3514,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3342 OutPacket(attach, ThrottleOutPacketType.Task); 3514 OutPacket(attach, ThrottleOutPacketType.Task);
3343 } 3515 }
3344 3516
3345 public void SendPrimitiveToClient( 3517 public void SendPrimitiveToClient(SendPrimitiveData data)
3346 ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape,
3347 Vector3 pos, Vector3 vel, Vector3 acc, Quaternion rotation, Vector3 rvel,
3348 uint flags, UUID objectID, UUID ownerID, string text, byte[] color,
3349 uint parentID, byte[] particleSystem, byte clickAction, byte material)
3350 { 3518 {
3351 byte[] textureanim = new byte[0]; 3519 if (data.priority == double.NaN)
3352 3520 {
3353 SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, vel, 3521 m_log.Error("[LLClientView] SendPrimitiveToClient received a NaN priority, dropping update");
3354 acc, rotation, rvel, flags, 3522 return;
3355 objectID, ownerID, text, color, parentID, particleSystem, 3523 }
3356 clickAction, material, textureanim, false, 0, UUID.Zero, UUID.Zero, 0, 0, 0);
3357 }
3358 3524
3359 public void SendPrimitiveToClient( 3525 Quaternion rotation = data.rotation;
3360 ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape,
3361 Vector3 pos, Vector3 velocity, Vector3 acceleration, Quaternion rotation, Vector3 rotational_velocity,
3362 uint flags,
3363 UUID objectID, UUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem,
3364 byte clickAction, byte material, byte[] textureanim, bool attachment, uint AttachPoint, UUID AssetId, UUID SoundId, double SoundGain, byte SoundFlags, double SoundRadius)
3365 {
3366 3526
3367 if (AttachPoint > 30 && ownerID != AgentId) // Someone else's HUD 3527 if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD
3368 return; 3528 return;
3369 if (primShape.PCode == 9 && primShape.State != 0 && parentID == 0) 3529 if (data.primShape.PCode == 9 && data.primShape.State != 0 && data.parentID == 0)
3370 return; 3530 return;
3371 3531
3372 if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) 3532 if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0.0f)
3373 rotation = Quaternion.Identity; 3533 rotation = Quaternion.Identity;
3374 3534
3375 ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(primShape, flags); 3535 ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data.primShape, data.flags);
3376 3536
3377 objectData.ID = localID; 3537 objectData.ID = data.localID;
3378 objectData.FullID = objectID; 3538 objectData.FullID = data.objectID;
3379 objectData.OwnerID = ownerID; 3539 objectData.OwnerID = data.ownerID;
3380 3540
3381 objectData.Text = Util.StringToBytes256(text); 3541 objectData.Text = Util.StringToBytes256(data.text);
3382 objectData.TextColor[0] = color[0]; 3542 objectData.TextColor[0] = data.color[0];
3383 objectData.TextColor[1] = color[1]; 3543 objectData.TextColor[1] = data.color[1];
3384 objectData.TextColor[2] = color[2]; 3544 objectData.TextColor[2] = data.color[2];
3385 objectData.TextColor[3] = color[3]; 3545 objectData.TextColor[3] = data.color[3];
3386 objectData.ParentID = parentID; 3546 objectData.ParentID = data.parentID;
3387 objectData.PSBlock = particleSystem; 3547 objectData.PSBlock = data.particleSystem;
3388 objectData.ClickAction = clickAction; 3548 objectData.ClickAction = data.clickAction;
3389 objectData.Material = material; 3549 objectData.Material = data.material;
3390 objectData.Flags = 0; 3550 objectData.Flags = 0;
3391 3551
3392 if (attachment) 3552 if (data.attachment)
3393 { 3553 {
3394 // Necessary??? 3554 // Necessary???
3395 objectData.JointAxisOrAnchor = new Vector3(0, 0, 2); 3555 objectData.JointAxisOrAnchor = new Vector3(0, 0, 2);
@@ -3397,14 +3557,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3397 3557
3398 // Item from inventory??? 3558 // Item from inventory???
3399 objectData.NameValue = 3559 objectData.NameValue =
3400 Utils.StringToBytes("AttachItemID STRING RW SV " + AssetId.Guid); 3560 Utils.StringToBytes("AttachItemID STRING RW SV " + data.AssetId.Guid);
3401 objectData.State = (byte)((AttachPoint % 16) * 16 + (AttachPoint / 16)); 3561 objectData.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16));
3402 } 3562 }
3403 3563
3404 // Xantor 20080528: Send sound info as well 3564 // Xantor 20080528: Send sound info as well
3405 // Xantor 20080530: Zero out everything if there's no SoundId, so zerocompression will work again 3565 // Xantor 20080530: Zero out everything if there's no SoundId, so zerocompression will work again
3406 objectData.Sound = SoundId; 3566 objectData.Sound = data.SoundId;
3407 if (SoundId == UUID.Zero) 3567 if (data.SoundId == UUID.Zero)
3408 { 3568 {
3409 objectData.OwnerID = UUID.Zero; 3569 objectData.OwnerID = UUID.Zero;
3410 objectData.Gain = 0.0f; 3570 objectData.Gain = 0.0f;
@@ -3413,39 +3573,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3413 } 3573 }
3414 else 3574 else
3415 { 3575 {
3416 objectData.OwnerID = ownerID; 3576 objectData.OwnerID = data.ownerID;
3417 objectData.Gain = (float)SoundGain; 3577 objectData.Gain = (float)data.SoundVolume;
3418 objectData.Radius = (float)SoundRadius; 3578 objectData.Radius = (float)data.SoundRadius;
3419 objectData.Flags = SoundFlags; 3579 objectData.Flags = data.SoundFlags;
3420 } 3580 }
3421 3581
3422 byte[] pb = pos.GetBytes(); 3582 byte[] pb = data.pos.GetBytes();
3423 Array.Copy(pb, 0, objectData.ObjectData, 0, pb.Length); 3583 Buffer.BlockCopy(pb, 0, objectData.ObjectData, 0, pb.Length);
3424 3584
3425 byte[] vel = velocity.GetBytes(); 3585 byte[] vel = data.vel.GetBytes();
3426 Array.Copy(vel, 0, objectData.ObjectData, pb.Length, vel.Length); 3586 Buffer.BlockCopy(vel, 0, objectData.ObjectData, pb.Length, vel.Length);
3427 3587
3428 byte[] rot = rotation.GetBytes(); 3588 byte[] rot = rotation.GetBytes();
3429 Array.Copy(rot, 0, objectData.ObjectData, 36, rot.Length); 3589 Buffer.BlockCopy(rot, 0, objectData.ObjectData, 36, rot.Length);
3430 3590
3431 byte[] rvel = rotational_velocity.GetBytes(); 3591 byte[] rvel = data.rvel.GetBytes();
3432 Array.Copy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length); 3592 Buffer.BlockCopy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length);
3433 3593
3434 if (textureanim.Length > 0) 3594 if (data.textureanim.Length > 0)
3435 { 3595 {
3436 objectData.TextureAnim = textureanim; 3596 objectData.TextureAnim = data.textureanim;
3437 } 3597 }
3438 3598
3439 lock (m_primFullUpdates) 3599 lock (m_primFullUpdates.SyncRoot)
3440 { 3600 m_primFullUpdates.Enqueue(data.priority, objectData, data.localID);
3441 if (m_primFullUpdates.Count == 0)
3442 m_primFullUpdateTimer.Start();
3443
3444 m_primFullUpdates.Add(objectData);
3445
3446 if (m_primFullUpdates.Count >= m_primFullUpdatesPerPacket)
3447 ProcessPrimFullUpdates(this, null);
3448 }
3449 } 3601 }
3450 3602
3451 void HandleQueueEmpty(ThrottleOutPacketType queue) 3603 void HandleQueueEmpty(ThrottleOutPacketType queue)
@@ -3455,6 +3607,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3455 case ThrottleOutPacketType.Texture: 3607 case ThrottleOutPacketType.Texture:
3456 ProcessTextureRequests(); 3608 ProcessTextureRequests();
3457 break; 3609 break;
3610 case ThrottleOutPacketType.State:
3611 int count = 0;
3612
3613 lock (m_avatarTerseUpdates.SyncRoot)
3614 count = m_avatarTerseUpdates.Count;
3615 if (count > 0)
3616 {
3617 ProcessAvatarTerseUpdates();
3618 return;
3619 }
3620
3621 lock (m_primFullUpdates.SyncRoot)
3622 count = m_primFullUpdates.Count;
3623 if (count > 0)
3624 {
3625 ProcessPrimFullUpdates();
3626 return;
3627 }
3628
3629 lock (m_primTerseUpdates.SyncRoot)
3630 count = m_primTerseUpdates.Count;
3631 if (count > 0)
3632 {
3633 ProcessPrimTerseUpdates();
3634 return;
3635 }
3636 break;
3458 } 3637 }
3459 } 3638 }
3460 3639
@@ -3464,18 +3643,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3464 m_imageManager.ProcessImageQueue(m_textureSendLimit); 3643 m_imageManager.ProcessImageQueue(m_textureSendLimit);
3465 } 3644 }
3466 3645
3467 void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) 3646 void ProcessPrimFullUpdates()
3468 { 3647 {
3469 lock (m_primFullUpdates) 3648 lock (m_primFullUpdates.SyncRoot)
3470 { 3649 {
3471 if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled)
3472 {
3473 lock (m_primFullUpdateTimer)
3474 m_primFullUpdateTimer.Stop();
3475
3476 return;
3477 }
3478
3479 ObjectUpdatePacket outPacket = 3650 ObjectUpdatePacket outPacket =
3480 (ObjectUpdatePacket)PacketPool.Instance.GetPacket( 3651 (ObjectUpdatePacket)PacketPool.Instance.GetPacket(
3481 PacketType.ObjectUpdate); 3652 PacketType.ObjectUpdate);
@@ -3495,74 +3666,63 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3495 byte[] zerobuffer = new byte[1024]; 3666 byte[] zerobuffer = new byte[1024];
3496 byte[] blockbuffer = new byte[1024]; 3667 byte[] blockbuffer = new byte[1024];
3497 3668
3669 Queue<ObjectUpdatePacket.ObjectDataBlock> updates = new Queue<ObjectUpdatePacket.ObjectDataBlock>();
3670
3498 for (count = 0 ; count < max ; count++) 3671 for (count = 0 ; count < max ; count++)
3499 { 3672 {
3500 int length = 0; 3673 int length = 0;
3501 m_primFullUpdates[count].ToBytes(blockbuffer, ref length); 3674 m_primFullUpdates.Peek().ToBytes(blockbuffer, ref length);
3502 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); 3675 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer);
3503 if (size + length > Packet.MTU) 3676 if (size + length > Packet.MTU)
3504 break; 3677 break;
3505 size += length; 3678 size += length;
3679 updates.Enqueue(m_primFullUpdates.Dequeue());
3506 } 3680 }
3507 3681
3508 outPacket.ObjectData = 3682 outPacket.ObjectData =
3509 new ObjectUpdatePacket.ObjectDataBlock[count]; 3683 new ObjectUpdatePacket.ObjectDataBlock[count];
3510 3684
3511 for (int index = 0 ; index < count ; index++) 3685 for (int index = 0 ; index < count ; index++)
3512 { 3686 outPacket.ObjectData[index] = updates.Dequeue();
3513 outPacket.ObjectData[index] = m_primFullUpdates[0];
3514 m_primFullUpdates.RemoveAt(0);
3515 }
3516 3687
3517 outPacket.Header.Zerocoded = true; 3688 outPacket.Header.Zerocoded = true;
3518 OutPacket(outPacket, ThrottleOutPacketType.State); 3689 OutPacket(outPacket, ThrottleOutPacketType.State);
3519
3520 if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled)
3521 lock (m_primFullUpdateTimer)
3522 m_primFullUpdateTimer.Stop();
3523 } 3690 }
3524 } 3691 }
3525 3692
3526 /// <summary> 3693 /// <summary>
3527 /// 3694 ///
3528 /// </summary> 3695 /// </summary>
3529 public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, 3696 //public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position,
3530 Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) 3697 // Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint)
3698 public void SendPrimTerseUpdate(SendPrimitiveTerseData data)
3531 { 3699 {
3532 if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD 3700 if (data.priority == double.NaN)
3701 {
3702 m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update");
3703 return;
3704 }
3705
3706 Quaternion rotation = data.rotation;
3707
3708 if (data.attachPoint > 30 && data.owner != AgentId) // Someone else's HUD
3533 return; 3709 return;
3534 3710
3535 if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) 3711 if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0)
3536 rotation = Quaternion.Identity; 3712 rotation = Quaternion.Identity;
3537 3713
3538 ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = 3714 ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData =
3539 CreatePrimImprovedBlock(localID, position, rotation, 3715 CreatePrimImprovedBlock(data.localID, data.position, rotation,
3540 velocity, rotationalvelocity, state); 3716 data.velocity, data.rotationalvelocity, data.state);
3541 3717
3542 lock (m_primTerseUpdates) 3718 lock (m_primTerseUpdates.SyncRoot)
3543 { 3719 m_primTerseUpdates.Enqueue(data.priority, objectData, data.localID);
3544 if (m_primTerseUpdates.Count == 0)
3545 m_primTerseUpdateTimer.Start();
3546
3547 m_primTerseUpdates.Add(objectData);
3548
3549 if (m_primTerseUpdates.Count >= m_primTerseUpdatesPerPacket)
3550 ProcessPrimTerseUpdates(this, null);
3551 }
3552 } 3720 }
3553 3721
3554 void ProcessPrimTerseUpdates(object sender, ElapsedEventArgs e) 3722 void ProcessPrimTerseUpdates()
3555 { 3723 {
3556 lock (m_primTerseUpdates) 3724 lock (m_primTerseUpdates.SyncRoot)
3557 { 3725 {
3558 if (m_primTerseUpdates.Count == 0)
3559 {
3560 lock (m_primTerseUpdateTimer)
3561 m_primTerseUpdateTimer.Stop();
3562
3563 return;
3564 }
3565
3566 ImprovedTerseObjectUpdatePacket outPacket = 3726 ImprovedTerseObjectUpdatePacket outPacket =
3567 (ImprovedTerseObjectUpdatePacket) 3727 (ImprovedTerseObjectUpdatePacket)
3568 PacketPool.Instance.GetPacket( 3728 PacketPool.Instance.GetPacket(
@@ -3583,14 +3743,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3583 byte[] zerobuffer = new byte[1024]; 3743 byte[] zerobuffer = new byte[1024];
3584 byte[] blockbuffer = new byte[1024]; 3744 byte[] blockbuffer = new byte[1024];
3585 3745
3746 Queue<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> updates = new Queue<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
3747
3586 for (count = 0 ; count < max ; count++) 3748 for (count = 0 ; count < max ; count++)
3587 { 3749 {
3588 int length = 0; 3750 int length = 0;
3589 m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); 3751 m_primTerseUpdates.Peek().ToBytes(blockbuffer, ref length);
3590 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); 3752 length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer);
3591 if (size + length > Packet.MTU) 3753 if (size + length > Packet.MTU)
3592 break; 3754 break;
3593 size += length; 3755 size += length;
3756 updates.Enqueue(m_primTerseUpdates.Dequeue());
3594 } 3757 }
3595 3758
3596 outPacket.ObjectData = 3759 outPacket.ObjectData =
@@ -3598,18 +3761,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3598 ObjectDataBlock[count]; 3761 ObjectDataBlock[count];
3599 3762
3600 for (int index = 0 ; index < count ; index++) 3763 for (int index = 0 ; index < count ; index++)
3601 { 3764 outPacket.ObjectData[index] = updates.Dequeue();
3602 outPacket.ObjectData[index] = m_primTerseUpdates[0];
3603 m_primTerseUpdates.RemoveAt(0);
3604 }
3605 3765
3606 outPacket.Header.Reliable = false; 3766 outPacket.Header.Reliable = false;
3607 outPacket.Header.Zerocoded = true; 3767 outPacket.Header.Zerocoded = true;
3608 OutPacket(outPacket, ThrottleOutPacketType.State); 3768 OutPacket(outPacket, ThrottleOutPacketType.State);
3609
3610 if (m_primTerseUpdates.Count == 0)
3611 lock (m_primTerseUpdateTimer)
3612 m_primTerseUpdateTimer.Stop();
3613 } 3769 }
3614 } 3770 }
3615 3771
@@ -3617,15 +3773,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3617 { 3773 {
3618 while (m_primFullUpdates.Count > 0) 3774 while (m_primFullUpdates.Count > 0)
3619 { 3775 {
3620 ProcessPrimFullUpdates(this, null); 3776 ProcessPrimFullUpdates();
3621 } 3777 }
3622 while (m_primTerseUpdates.Count > 0) 3778 while (m_primTerseUpdates.Count > 0)
3623 { 3779 {
3624 ProcessPrimTerseUpdates(this, null); 3780 ProcessPrimTerseUpdates();
3625 } 3781 }
3626 while (m_avatarTerseUpdates.Count > 0) 3782 while (m_avatarTerseUpdates.Count > 0)
3627 { 3783 {
3628 ProcessAvatarTerseUpdates(this, null); 3784 ProcessAvatarTerseUpdates();
3629 } 3785 }
3630 } 3786 }
3631 3787
@@ -10371,5 +10527,136 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10371 pack.TextureData.TextureID = textureID; 10527 pack.TextureData.TextureID = textureID;
10372 OutPacket(pack, ThrottleOutPacketType.Task); 10528 OutPacket(pack, ThrottleOutPacketType.Task);
10373 } 10529 }
10530
10531 #region PriorityQueue
10532 private class PriorityQueue<TPriority, TValue>
10533 {
10534 private MinHeap<MinHeapItem>[] heaps = new MinHeap<MinHeapItem>[1];
10535 private Dictionary<uint, LookupItem> lookup_table = new Dictionary<uint, LookupItem>();
10536 private Comparison<TPriority> comparison;
10537 private object sync_root = new object();
10538
10539 internal PriorityQueue() :
10540 this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, Comparer<TPriority>.Default) { }
10541 internal PriorityQueue(int capacity) :
10542 this(capacity, Comparer<TPriority>.Default) { }
10543 internal PriorityQueue(IComparer<TPriority> comparer) :
10544 this(new Comparison<TPriority>(comparer.Compare)) { }
10545 internal PriorityQueue(Comparison<TPriority> comparison) :
10546 this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, comparison) { }
10547 internal PriorityQueue(int capacity, IComparer<TPriority> comparer) :
10548 this(capacity, new Comparison<TPriority>(comparer.Compare)) { }
10549 internal PriorityQueue(int capacity, Comparison<TPriority> comparison)
10550 {
10551 for (int i = 0; i < heaps.Length; ++i)
10552 heaps[i] = new MinHeap<MinHeapItem>(capacity);
10553 this.comparison = comparison;
10554 }
10555
10556 internal object SyncRoot { get { return this.sync_root; } }
10557 internal int Count
10558 {
10559 get
10560 {
10561 int count = 0;
10562 for (int i = 0; i < heaps.Length; ++i)
10563 count = heaps[i].Count;
10564 return count;
10565 }
10566 }
10567
10568 internal bool Enqueue(TPriority priority, TValue value, uint local_id)
10569 {
10570 LookupItem item;
10571
10572 if (lookup_table.TryGetValue(local_id, out item))
10573 {
10574 item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.comparison);
10575 return false;
10576 }
10577 else
10578 {
10579 item.Heap = heaps[0];
10580 item.Heap.Add(new MinHeapItem(priority, value, local_id, this.comparison), ref item.Handle);
10581 lookup_table.Add(local_id, item);
10582 return true;
10583 }
10584 }
10585
10586 internal TValue Peek()
10587 {
10588 for (int i = 0; i < heaps.Length; ++i)
10589 if (heaps[i].Count > 0)
10590 return heaps[i].Min().Value;
10591 throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
10592 }
10593
10594 internal TValue Dequeue()
10595 {
10596 for (int i = 0; i < heaps.Length; ++i)
10597 {
10598 if (heaps[i].Count > 0)
10599 {
10600 MinHeapItem item = heaps[i].RemoveMin();
10601 lookup_table.Remove(item.LocalID);
10602 return item.Value;
10603 }
10604 }
10605 throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
10606 }
10607
10608 #region MinHeapItem
10609 private struct MinHeapItem : IComparable<MinHeapItem>
10610 {
10611 private TPriority priority;
10612 private TValue value;
10613 private uint local_id;
10614 private Comparison<TPriority> comparison;
10615
10616 internal MinHeapItem(TPriority priority, TValue value, uint local_id) :
10617 this(priority, value, local_id, Comparer<TPriority>.Default) { }
10618 internal MinHeapItem(TPriority priority, TValue value, uint local_id, IComparer<TPriority> comparer) :
10619 this(priority, value, local_id, new Comparison<TPriority>(comparer.Compare)) { }
10620 internal MinHeapItem(TPriority priority, TValue value, uint local_id, Comparison<TPriority> comparison)
10621 {
10622 this.priority = priority;
10623 this.value = value;
10624 this.local_id = local_id;
10625 this.comparison = comparison;
10626 }
10627
10628 internal TPriority Priority { get { return this.priority; } }
10629 internal TValue Value { get { return this.value; } }
10630 internal uint LocalID { get { return this.local_id; } }
10631
10632 public override string ToString()
10633 {
10634 StringBuilder sb = new StringBuilder();
10635 sb.Append("[");
10636 if (this.priority != null)
10637 sb.Append(this.priority.ToString());
10638 sb.Append(",");
10639 if (this.value != null)
10640 sb.Append(this.value.ToString());
10641 sb.Append("]");
10642 return sb.ToString();
10643 }
10644
10645 public int CompareTo(MinHeapItem other)
10646 {
10647 return this.comparison(this.priority, other.priority);
10648 }
10649 }
10650 #endregion
10651
10652 #region LookupItem
10653 private struct LookupItem {
10654 internal MinHeap<MinHeapItem> Heap;
10655 internal IHandle Handle;
10656 }
10657 #endregion
10658 }
10659 #endregion
10660
10374 } 10661 }
10375} 10662}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 4eee6b6..8c42ca4 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -170,7 +170,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
170 { 170 {
171 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 171 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
172 172
173 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
173 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 174 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
175 // Initialize the token buckets that control the throttling for each category
174 m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); 176 m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type));
175 } 177 }
176 178
@@ -293,36 +295,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP
293 int state = (int)((float)task * STATE_TASK_PERCENTAGE); 295 int state = (int)((float)task * STATE_TASK_PERCENTAGE);
294 task -= state; 296 task -= state;
295 297
296 int ceiling = Int32.MaxValue; 298 // Make sure none of the throttles are set below our packet MTU,
297 if (m_defaultThrottleRates.Total != 0) 299 // otherwise a throttle could become permanently clogged
298 { 300 resend = Math.Max(resend, Packet.MTU);
299 ceiling = m_defaultThrottleRates.Total; 301 land = Math.Max(land, Packet.MTU);
300 if (ceiling < Packet.MTU) ceiling = Packet.MTU; 302 wind = Math.Max(wind, Packet.MTU);
301 } 303 cloud = Math.Max(cloud, Packet.MTU);
302 304 task = Math.Max(task, Packet.MTU);
303 resend = Utils.Clamp(resend, Packet.MTU, ceiling); 305 texture = Math.Max(texture, Packet.MTU);
304 land = Utils.Clamp(land, Packet.MTU, ceiling); 306 asset = Math.Max(asset, Packet.MTU);
305 wind = Utils.Clamp(wind, Packet.MTU, ceiling); 307 state = Math.Max(state, Packet.MTU);
306 cloud = Utils.Clamp(cloud, Packet.MTU, ceiling);
307 task = Utils.Clamp(task, Packet.MTU, ceiling);
308 texture = Utils.Clamp(texture, Packet.MTU, ceiling);
309 asset = Utils.Clamp(asset, Packet.MTU, ceiling);
310 state = Utils.Clamp(state, Packet.MTU, ceiling);
311 308
312 int total = resend + land + wind + cloud + task + texture + asset + state; 309 int total = resend + land + wind + cloud + task + texture + asset + state;
313 int taskTotal = task + state;
314 310
315 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}", 311 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}",
316 AgentID, resend, land, wind, cloud, task, texture, asset, state, total); 312 AgentID, resend, land, wind, cloud, task, texture, asset, state, total);
317 313
318 SetThrottle(ThrottleOutPacketType.Resend, resend, resend); 314 // Update the token buckets with new throttle values
319 SetThrottle(ThrottleOutPacketType.Land, land, land); 315 TokenBucket bucket;
320 SetThrottle(ThrottleOutPacketType.Wind, wind, wind); 316
321 SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud); 317 bucket = m_throttle;
322 SetThrottle(ThrottleOutPacketType.Task, task, taskTotal); 318 bucket.MaxBurst = total;
323 SetThrottle(ThrottleOutPacketType.Texture, texture, texture); 319
324 SetThrottle(ThrottleOutPacketType.Asset, asset, asset); 320 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
325 SetThrottle(ThrottleOutPacketType.State, state, taskTotal); 321 bucket.DripRate = bucket.MaxBurst = resend;
322
323 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
324 bucket.DripRate = bucket.MaxBurst = land;
325
326 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
327 bucket.DripRate = bucket.MaxBurst = wind;
328
329 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
330 bucket.DripRate = bucket.MaxBurst = cloud;
331
332 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
333 bucket.DripRate = bucket.MaxBurst = asset;
334
335 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
336 bucket.DripRate = task + state + texture;
337 bucket.MaxBurst = task + state + texture;
338
339 bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
340 bucket.DripRate = state + texture;
341 bucket.MaxBurst = state + texture;
342
343 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
344 bucket.DripRate = texture;
345 bucket.MaxBurst = texture;
326 } 346 }
327 347
328 public byte[] GetThrottlesPacked() 348 public byte[] GetThrottlesPacked()
@@ -342,17 +362,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
342 return data; 362 return data;
343 } 363 }
344 364
345 public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst)
346 {
347 int i = (int)category;
348 if (i >= 0 && i < m_throttleCategories.Length)
349 {
350 TokenBucket bucket = m_throttleCategories[(int)category];
351 bucket.DripRate = rate;
352 bucket.MaxBurst = maxBurst;
353 }
354 }
355
356 public bool EnqueueOutgoing(OutgoingPacket packet) 365 public bool EnqueueOutgoing(OutgoingPacket packet)
357 { 366 {
358 int category = (int)packet.Category; 367 int category = (int)packet.Category;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 545a0bc..b11a80d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -285,7 +285,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 // The packet grew larger than the bufferSize while zerocoding. 285 // The packet grew larger than the bufferSize while zerocoding.
286 // Remove the MSG_ZEROCODED flag and send the unencoded data 286 // Remove the MSG_ZEROCODED flag and send the unencoded data
287 // instead 287 // instead
288 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); 288 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength +
289 " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag");
289 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); 290 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
290 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 291 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
291 } 292 }
@@ -513,7 +514,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
513 IClientAPI client; 514 IClientAPI client;
514 if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) 515 if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView))
515 { 516 {
516 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + 517 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
517 " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); 518 " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
518 return; 519 return;
519 } 520 }