diff options
author | Melanie | 2009-10-22 07:12:10 +0100 |
---|---|---|
committer | Melanie | 2009-10-22 07:12:10 +0100 |
commit | c4969d47d9bbc22b37054451cd31451ca8d8c78a (patch) | |
tree | 788e3b034254bcf068ca950ee97a78b6aa07b386 /OpenSim/Region/ClientStack/LindenUDP | |
parent | Merge branch 'master' into vehicles (diff) | |
parent | Remove the "mel_t" from version string (diff) | |
download | opensim-SC_OLD-c4969d47d9bbc22b37054451cd31451ca8d8c78a.zip opensim-SC_OLD-c4969d47d9bbc22b37054451cd31451ca8d8c78a.tar.gz opensim-SC_OLD-c4969d47d9bbc22b37054451cd31451ca8d8c78a.tar.bz2 opensim-SC_OLD-c4969d47d9bbc22b37054451cd31451ca8d8c78a.tar.xz |
Merge branch 'master' into vehicles
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 1857 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | 2 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 219 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 421 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs | 9 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | 217 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | 162 |
7 files changed, 1647 insertions, 1240 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 05a2a63..0ba76ec 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -45,12 +45,50 @@ using OpenSim.Region.Framework.Interfaces; | |||
45 | using OpenSim.Region.Framework.Scenes; | 45 | using OpenSim.Region.Framework.Scenes; |
46 | using OpenSim.Region.Framework.Scenes.Hypergrid; | 46 | using OpenSim.Region.Framework.Scenes.Hypergrid; |
47 | using OpenSim.Services.Interfaces; | 47 | using OpenSim.Services.Interfaces; |
48 | using Timer=System.Timers.Timer; | 48 | using Timer = System.Timers.Timer; |
49 | using AssetLandmark = OpenSim.Framework.AssetLandmark; | 49 | using AssetLandmark = OpenSim.Framework.AssetLandmark; |
50 | using Nini.Config; | 50 | using Nini.Config; |
51 | 51 | ||
52 | namespace OpenSim.Region.ClientStack.LindenUDP | 52 | namespace 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> |
@@ -257,6 +295,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
257 | public event MuteListRequest OnMuteListRequest; | 295 | public event MuteListRequest OnMuteListRequest; |
258 | public event AvatarInterestUpdate OnAvatarInterestUpdate; | 296 | public event AvatarInterestUpdate OnAvatarInterestUpdate; |
259 | public event PlacesQuery OnPlacesQuery; | 297 | public event PlacesQuery OnPlacesQuery; |
298 | public event AgentFOV OnAgentFOV; | ||
260 | 299 | ||
261 | #endregion Events | 300 | #endregion Events |
262 | 301 | ||
@@ -282,12 +321,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
282 | private readonly IGroupsModule m_GroupsModule; | 321 | private readonly IGroupsModule m_GroupsModule; |
283 | 322 | ||
284 | private int m_cachedTextureSerial; | 323 | private int m_cachedTextureSerial; |
285 | private Timer m_avatarTerseUpdateTimer; | 324 | private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates; |
286 | private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | 325 | private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates; |
287 | private Timer m_primTerseUpdateTimer; | 326 | private PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates; |
288 | private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | ||
289 | private Timer m_primFullUpdateTimer; | ||
290 | private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates = new List<ObjectUpdatePacket.ObjectDataBlock>(); | ||
291 | private int m_moneyBalance; | 327 | private int m_moneyBalance; |
292 | private int m_animationSequenceNumber = 1; | 328 | private int m_animationSequenceNumber = 1; |
293 | private bool m_SendLogoutPacketWhenClosing = true; | 329 | private bool m_SendLogoutPacketWhenClosing = true; |
@@ -296,26 +332,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
296 | 332 | ||
297 | protected Dictionary<PacketType, PacketMethod> m_packetHandlers = new Dictionary<PacketType, PacketMethod>(); | 333 | protected Dictionary<PacketType, PacketMethod> m_packetHandlers = new Dictionary<PacketType, PacketMethod>(); |
298 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers | 334 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers |
299 | protected IScene m_scene; | 335 | protected Scene m_scene; |
300 | protected LLImageManager m_imageManager; | 336 | protected LLImageManager m_imageManager; |
301 | protected string m_firstName; | 337 | protected string m_firstName; |
302 | protected string m_lastName; | 338 | protected string m_lastName; |
303 | protected Thread m_clientThread; | 339 | protected Thread m_clientThread; |
304 | protected Vector3 m_startpos; | 340 | protected Vector3 m_startpos; |
305 | protected EndPoint m_userEndPoint; | 341 | protected EndPoint m_userEndPoint; |
306 | protected UUID m_activeGroupID = UUID.Zero; | 342 | protected UUID m_activeGroupID; |
307 | protected string m_activeGroupName = String.Empty; | 343 | protected string m_activeGroupName = String.Empty; |
308 | protected ulong m_activeGroupPowers; | 344 | protected ulong m_activeGroupPowers; |
309 | protected Dictionary<UUID,ulong> m_groupPowers = new Dictionary<UUID, ulong>(); | 345 | protected Dictionary<UUID, ulong> m_groupPowers = new Dictionary<UUID, ulong>(); |
310 | protected int m_terrainCheckerCount; | 346 | protected int m_terrainCheckerCount; |
311 | 347 | protected uint m_agentFOVCounter; | |
312 | // LL uses these limits, apparently. Compressed terse would be 23, but we don't have that yet | 348 | |
313 | protected int m_primTerseUpdatesPerPacket = 10; | 349 | // These numbers are guesses at a decent tradeoff between responsiveness |
314 | protected int m_primFullUpdatesPerPacket = 14; | 350 | // of the interest list and throughput. Lower is more responsive, higher |
315 | protected int m_primTerseUpdateRate = 10; | 351 | // is better throughput |
316 | protected int m_primFullUpdateRate = 14; | 352 | protected int m_primTerseUpdatesPerPacket = 25; |
317 | protected int m_avatarTerseUpdateRate = 50; | 353 | protected int m_primFullUpdatesPerPacket = 100; |
318 | protected int m_avatarTerseUpdatesPerPacket = 5; | 354 | protected int m_avatarTerseUpdatesPerPacket = 10; |
319 | /// <summary>Number of texture packets to put on the queue each time the | 355 | /// <summary>Number of texture packets to put on the queue each time the |
320 | /// OnQueueEmpty event is triggered for the texture category</summary> | 356 | /// OnQueueEmpty event is triggered for the texture category</summary> |
321 | protected int m_textureSendLimit = 20; | 357 | protected int m_textureSendLimit = 20; |
@@ -369,21 +405,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
369 | /// <summary> | 405 | /// <summary> |
370 | /// Constructor | 406 | /// Constructor |
371 | /// </summary> | 407 | /// </summary> |
372 | public LLClientView(EndPoint remoteEP, IScene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo, | 408 | public LLClientView(EndPoint remoteEP, Scene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo, |
373 | UUID agentId, UUID sessionId, uint circuitCode) | 409 | UUID agentId, UUID sessionId, uint circuitCode) |
374 | { | 410 | { |
375 | RegisterInterface<IClientIM>(this); | 411 | RegisterInterface<IClientIM>(this); |
376 | RegisterInterface<IClientChat>(this); | 412 | RegisterInterface<IClientChat>(this); |
377 | RegisterInterface<IClientIPEndpoint>(this); | 413 | RegisterInterface<IClientIPEndpoint>(this); |
378 | 414 | ||
379 | InitDefaultAnimations(); | 415 | InitDefaultAnimations(); |
380 | 416 | ||
381 | m_scene = scene; | 417 | m_scene = scene; |
418 | |||
419 | m_avatarTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | ||
420 | m_primTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | ||
421 | m_primFullUpdates = new PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>(m_scene.Entities.Count); | ||
422 | |||
382 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | 423 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); |
383 | m_hyperAssets = m_scene.RequestModuleInterface<IHyperAssetService>(); | 424 | m_hyperAssets = m_scene.RequestModuleInterface<IHyperAssetService>(); |
384 | m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>(); | 425 | m_GroupsModule = scene.RequestModuleInterface<IGroupsModule>(); |
385 | m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>()); | 426 | m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface<IJ2KDecoder>()); |
386 | m_channelVersion = Utils.StringToBytes(scene.GetSimulatorVersion()); | 427 | m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion()); |
387 | m_agentId = agentId; | 428 | m_agentId = agentId; |
388 | m_sessionId = sessionId; | 429 | m_sessionId = sessionId; |
389 | m_secureSessionId = sessionInfo.LoginInfo.SecureSession; | 430 | m_secureSessionId = sessionInfo.LoginInfo.SecureSession; |
@@ -438,25 +479,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
438 | // Remove ourselves from the scene | 479 | // Remove ourselves from the scene |
439 | m_scene.RemoveClient(AgentId); | 480 | m_scene.RemoveClient(AgentId); |
440 | 481 | ||
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 | 482 | // We can't reach into other scenes and close the connection |
453 | // We need to do this over grid communications | 483 | // We need to do this over grid communications |
454 | //m_scene.CloseAllAgents(CircuitCode); | 484 | //m_scene.CloseAllAgents(CircuitCode); |
455 | 485 | ||
456 | m_avatarTerseUpdateTimer.Dispose(); | ||
457 | m_primTerseUpdateTimer.Dispose(); | ||
458 | m_primFullUpdateTimer.Dispose(); | ||
459 | |||
460 | // Disable UDP handling for this client | 486 | // Disable UDP handling for this client |
461 | m_udpClient.Shutdown(); | 487 | m_udpClient.Shutdown(); |
462 | 488 | ||
@@ -474,7 +500,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
474 | kupack.UserInfo.SessionID = SessionId; | 500 | kupack.UserInfo.SessionID = SessionId; |
475 | kupack.TargetBlock.TargetIP = 0; | 501 | kupack.TargetBlock.TargetIP = 0; |
476 | kupack.TargetBlock.TargetPort = 0; | 502 | kupack.TargetBlock.TargetPort = 0; |
477 | kupack.UserInfo.Reason = Utils.StringToBytes(message); | 503 | kupack.UserInfo.Reason = Util.StringToBytes256(message); |
478 | OutPacket(kupack, ThrottleOutPacketType.Task); | 504 | OutPacket(kupack, ThrottleOutPacketType.Task); |
479 | // You must sleep here or users get no message! | 505 | // You must sleep here or users get no message! |
480 | Thread.Sleep(500); | 506 | Thread.Sleep(500); |
@@ -483,18 +509,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
483 | 509 | ||
484 | public void Stop() | 510 | public void Stop() |
485 | { | 511 | { |
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 | |||
491 | if (m_primTerseUpdateTimer.Enabled) | ||
492 | lock (m_primTerseUpdateTimer) | ||
493 | m_primTerseUpdateTimer.Stop(); | ||
494 | 512 | ||
495 | if (m_primFullUpdateTimer.Enabled) | ||
496 | lock (m_primFullUpdateTimer) | ||
497 | m_primFullUpdateTimer.Stop(); | ||
498 | } | 513 | } |
499 | 514 | ||
500 | #endregion Client Methods | 515 | #endregion Client Methods |
@@ -590,18 +605,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
590 | 605 | ||
591 | public virtual void Start() | 606 | public virtual void Start() |
592 | { | 607 | { |
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); | 608 | m_scene.AddNewClient(this); |
606 | 609 | ||
607 | RefreshGroupMembership(); | 610 | RefreshGroupMembership(); |
@@ -618,7 +621,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
618 | } | 621 | } |
619 | 622 | ||
620 | // Sound | 623 | // Sound |
621 | public void SoundTrigger(UUID soundId, UUID owerid, UUID Objectid,UUID ParentId,float Gain, Vector3 Position,UInt64 Handle) | 624 | public void SoundTrigger(UUID soundId, UUID owerid, UUID Objectid, UUID ParentId, float Gain, Vector3 Position, UInt64 Handle) |
622 | { | 625 | { |
623 | } | 626 | } |
624 | 627 | ||
@@ -642,7 +645,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
642 | handshake.RegionInfo.WaterHeight = args.waterHeight; | 645 | handshake.RegionInfo.WaterHeight = args.waterHeight; |
643 | 646 | ||
644 | handshake.RegionInfo.RegionFlags = args.regionFlags; | 647 | handshake.RegionInfo.RegionFlags = args.regionFlags; |
645 | handshake.RegionInfo.SimName = Utils.StringToBytes(args.regionName); | 648 | handshake.RegionInfo.SimName = Util.StringToBytes256(args.regionName); |
646 | handshake.RegionInfo.SimOwner = args.SimOwner; | 649 | handshake.RegionInfo.SimOwner = args.SimOwner; |
647 | handshake.RegionInfo.TerrainBase0 = args.terrainBase0; | 650 | handshake.RegionInfo.TerrainBase0 = args.terrainBase0; |
648 | handshake.RegionInfo.TerrainBase1 = args.terrainBase1; | 651 | handshake.RegionInfo.TerrainBase1 = args.terrainBase1; |
@@ -655,7 +658,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
655 | handshake.RegionInfo.CacheID = UUID.Random(); //I guess this is for the client to remember an old setting? | 658 | handshake.RegionInfo.CacheID = UUID.Random(); //I guess this is for the client to remember an old setting? |
656 | handshake.RegionInfo2 = new RegionHandshakePacket.RegionInfo2Block(); | 659 | handshake.RegionInfo2 = new RegionHandshakePacket.RegionInfo2Block(); |
657 | handshake.RegionInfo2.RegionID = regionInfo.RegionID; | 660 | handshake.RegionInfo2.RegionID = regionInfo.RegionID; |
658 | 661 | ||
659 | handshake.RegionInfo3 = new RegionHandshakePacket.RegionInfo3Block(); | 662 | handshake.RegionInfo3 = new RegionHandshakePacket.RegionInfo3Block(); |
660 | handshake.RegionInfo3.CPUClassID = 9; | 663 | handshake.RegionInfo3.CPUClassID = 9; |
661 | handshake.RegionInfo3.CPURatio = 1; | 664 | handshake.RegionInfo3.CPURatio = 1; |
@@ -698,11 +701,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
698 | { | 701 | { |
699 | ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator); | 702 | ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator); |
700 | reply.ChatData.Audible = audible; | 703 | reply.ChatData.Audible = audible; |
701 | reply.ChatData.Message = Utils.StringToBytes(message); | 704 | reply.ChatData.Message = Util.StringToBytes1024(message); |
702 | reply.ChatData.ChatType = type; | 705 | reply.ChatData.ChatType = type; |
703 | reply.ChatData.SourceType = source; | 706 | reply.ChatData.SourceType = source; |
704 | reply.ChatData.Position = fromPos; | 707 | reply.ChatData.Position = fromPos; |
705 | reply.ChatData.FromName = Utils.StringToBytes(fromName); | 708 | reply.ChatData.FromName = Util.StringToBytes256(fromName); |
706 | reply.ChatData.OwnerID = fromAgentID; | 709 | reply.ChatData.OwnerID = fromAgentID; |
707 | reply.ChatData.SourceID = fromAgentID; | 710 | reply.ChatData.SourceID = fromAgentID; |
708 | 711 | ||
@@ -723,7 +726,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
723 | 726 | ||
724 | msg.AgentData.AgentID = new UUID(im.fromAgentID); | 727 | msg.AgentData.AgentID = new UUID(im.fromAgentID); |
725 | msg.AgentData.SessionID = UUID.Zero; | 728 | msg.AgentData.SessionID = UUID.Zero; |
726 | msg.MessageBlock.FromAgentName = Utils.StringToBytes(im.fromAgentName); | 729 | msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName); |
727 | msg.MessageBlock.Dialog = im.dialog; | 730 | msg.MessageBlock.Dialog = im.dialog; |
728 | msg.MessageBlock.FromGroup = im.fromGroup; | 731 | msg.MessageBlock.FromGroup = im.fromGroup; |
729 | if (im.imSessionID == UUID.Zero.Guid) | 732 | if (im.imSessionID == UUID.Zero.Guid) |
@@ -736,12 +739,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
736 | msg.MessageBlock.RegionID = new UUID(im.RegionID); | 739 | msg.MessageBlock.RegionID = new UUID(im.RegionID); |
737 | msg.MessageBlock.Timestamp = im.timestamp; | 740 | msg.MessageBlock.Timestamp = im.timestamp; |
738 | msg.MessageBlock.ToAgentID = new UUID(im.toAgentID); | 741 | msg.MessageBlock.ToAgentID = new UUID(im.toAgentID); |
739 | // Cap the message length at 1099. There is a limit in ImprovedInstantMessagePacket | 742 | msg.MessageBlock.Message = Util.StringToBytes1024(im.message); |
740 | // the limit is 1100 but a 0 byte gets added to mark the end of the string | ||
741 | if (im.message != null && im.message.Length > 1099) | ||
742 | msg.MessageBlock.Message = Utils.StringToBytes(im.message.Substring(0, 1099)); | ||
743 | else | ||
744 | msg.MessageBlock.Message = Utils.StringToBytes(im.message); | ||
745 | msg.MessageBlock.BinaryBucket = im.binaryBucket; | 743 | msg.MessageBlock.BinaryBucket = im.binaryBucket; |
746 | 744 | ||
747 | if (im.message.StartsWith("[grouptest]")) | 745 | if (im.message.StartsWith("[grouptest]")) |
@@ -759,7 +757,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
759 | eq.ChatterboxInvitation( | 757 | eq.ChatterboxInvitation( |
760 | new UUID("00000000-68f9-1111-024e-222222111123"), | 758 | new UUID("00000000-68f9-1111-024e-222222111123"), |
761 | "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0, | 759 | "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0, |
762 | false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Utils.StringToBytes("OpenSimulator Testing")); | 760 | false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing")); |
763 | 761 | ||
764 | eq.ChatterBoxSessionAgentListUpdates( | 762 | eq.ChatterBoxSessionAgentListUpdates( |
765 | new UUID("00000000-68f9-1111-024e-222222111123"), | 763 | new UUID("00000000-68f9-1111-024e-222222111123"), |
@@ -776,13 +774,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
776 | public void SendGenericMessage(string method, List<string> message) | 774 | public void SendGenericMessage(string method, List<string> message) |
777 | { | 775 | { |
778 | GenericMessagePacket gmp = new GenericMessagePacket(); | 776 | GenericMessagePacket gmp = new GenericMessagePacket(); |
779 | gmp.MethodData.Method = Utils.StringToBytes(method); | 777 | gmp.MethodData.Method = Util.StringToBytes256(method); |
780 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; | 778 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; |
781 | int i = 0; | 779 | int i = 0; |
782 | foreach (string val in message) | 780 | foreach (string val in message) |
783 | { | 781 | { |
784 | gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); | 782 | gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); |
785 | gmp.ParamList[i++].Parameter = Utils.StringToBytes(val); | 783 | gmp.ParamList[i++].Parameter = Util.StringToBytes256(val); |
786 | } | 784 | } |
787 | OutPacket(gmp, ThrottleOutPacketType.Task); | 785 | OutPacket(gmp, ThrottleOutPacketType.Task); |
788 | } | 786 | } |
@@ -793,7 +791,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
793 | /// <param name="map">heightmap</param> | 791 | /// <param name="map">heightmap</param> |
794 | public virtual void SendLayerData(float[] map) | 792 | public virtual void SendLayerData(float[] map) |
795 | { | 793 | { |
796 | ThreadPool.QueueUserWorkItem(DoSendLayerData, map); | 794 | Util.FireAndForget(DoSendLayerData, map); |
797 | } | 795 | } |
798 | 796 | ||
799 | /// <summary> | 797 | /// <summary> |
@@ -802,32 +800,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
802 | /// <param name="o"></param> | 800 | /// <param name="o"></param> |
803 | private void DoSendLayerData(object o) | 801 | private void DoSendLayerData(object o) |
804 | { | 802 | { |
805 | float[] map = (float[])o; | 803 | float[] map = LLHeightFieldMoronize((float[])o); |
806 | 804 | ||
807 | try | 805 | try |
808 | { | 806 | { |
809 | for (int y = 0; y < 16; y++) | 807 | //for (int y = 0; y < 16; y++) |
810 | { | 808 | //{ |
811 | // For some terrains, sending more than one terrain patch at once results in a libsecondlife exception | 809 | // for (int x = 0; x < 16; x++) |
812 | // see http://opensimulator.org/mantis/view.php?id=1662 | 810 | // { |
813 | //for (int x = 0; x < 16; x += 4) | 811 | // SendLayerData(x, y, map); |
814 | //{ | 812 | // } |
815 | // SendLayerPacket(map, y, x); | 813 | //} |
816 | // Thread.Sleep(150); | 814 | |
817 | //} | 815 | // Send LayerData in a spiral pattern. Fun! |
818 | for (int x = 0; x < 16; x++) | 816 | SendLayerTopRight(map, 0, 0, 15, 15); |
819 | { | ||
820 | SendLayerData(x, y, LLHeightFieldMoronize(map)); | ||
821 | Thread.Sleep(35); | ||
822 | } | ||
823 | } | ||
824 | } | 817 | } |
825 | catch (Exception e) | 818 | catch (Exception e) |
826 | { | 819 | { |
827 | m_log.Warn("[CLIENT]: ClientView.API.cs: SendLayerData() - Failed with exception " + e); | 820 | m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e); |
828 | } | 821 | } |
829 | } | 822 | } |
830 | 823 | ||
824 | private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2) | ||
825 | { | ||
826 | // Row | ||
827 | for (int i = x1; i <= x2; i++) | ||
828 | SendLayerData(i, y1, map); | ||
829 | |||
830 | // Column | ||
831 | for (int j = y1 + 1; j <= y2; j++) | ||
832 | SendLayerData(x2, j, map); | ||
833 | |||
834 | if (x2 - x1 > 0) | ||
835 | SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2); | ||
836 | } | ||
837 | |||
838 | void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2) | ||
839 | { | ||
840 | // Row in reverse | ||
841 | for (int i = x2; i >= x1; i--) | ||
842 | SendLayerData(i, y2, map); | ||
843 | |||
844 | // Column in reverse | ||
845 | for (int j = y2 - 1; j >= y1; j--) | ||
846 | SendLayerData(x1, j, map); | ||
847 | |||
848 | if (x2 - x1 > 0) | ||
849 | SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); | ||
850 | } | ||
851 | |||
831 | /// <summary> | 852 | /// <summary> |
832 | /// Sends a set of four patches (x, x+1, ..., x+3) to the client | 853 | /// Sends a set of four patches (x, x+1, ..., x+3) to the client |
833 | /// </summary> | 854 | /// </summary> |
@@ -856,22 +877,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
856 | { | 877 | { |
857 | try | 878 | try |
858 | { | 879 | { |
859 | int[] patches = new int[1]; | 880 | int[] patches = new int[] { py * 16 + px }; |
860 | int patchx, patchy; | 881 | float[] heightmap = (map.Length == 65536) ? |
861 | patchx = px; | 882 | map : |
862 | patchy = py; | 883 | LLHeightFieldMoronize(map); |
863 | 884 | ||
864 | patches[0] = patchx + 0 + patchy * 16; | 885 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); |
865 | 886 | layerpack.Header.Reliable = true; | |
866 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(((map.Length==65536)? map : LLHeightFieldMoronize(map)), patches); | ||
867 | layerpack.Header.Zerocoded = true; | ||
868 | 887 | ||
869 | OutPacket(layerpack, ThrottleOutPacketType.Land); | 888 | OutPacket(layerpack, ThrottleOutPacketType.Land); |
870 | |||
871 | } | 889 | } |
872 | catch (Exception e) | 890 | catch (Exception e) |
873 | { | 891 | { |
874 | m_log.Warn("[client]: ClientView.API.cs: SendLayerData() - Failed with exception " + e.ToString()); | 892 | m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e); |
875 | } | 893 | } |
876 | } | 894 | } |
877 | 895 | ||
@@ -900,7 +918,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
900 | Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256); | 918 | Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256); |
901 | } | 919 | } |
902 | 920 | ||
903 | |||
904 | //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536); | 921 | //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536); |
905 | 922 | ||
906 | return returnmap; | 923 | return returnmap; |
@@ -914,7 +931,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
914 | /// <param name="windSpeeds">16x16 array of wind speeds</param> | 931 | /// <param name="windSpeeds">16x16 array of wind speeds</param> |
915 | public virtual void SendWindData(Vector2[] windSpeeds) | 932 | public virtual void SendWindData(Vector2[] windSpeeds) |
916 | { | 933 | { |
917 | ThreadPool.QueueUserWorkItem(new WaitCallback(DoSendWindData), (object)windSpeeds); | 934 | Util.FireAndForget(DoSendWindData, windSpeeds); |
918 | } | 935 | } |
919 | 936 | ||
920 | /// <summary> | 937 | /// <summary> |
@@ -923,7 +940,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
923 | /// <param name="windSpeeds">16x16 array of cloud densities</param> | 940 | /// <param name="windSpeeds">16x16 array of cloud densities</param> |
924 | public virtual void SendCloudData(float[] cloudDensity) | 941 | public virtual void SendCloudData(float[] cloudDensity) |
925 | { | 942 | { |
926 | ThreadPool.QueueUserWorkItem(new WaitCallback(DoSendCloudData), (object)cloudDensity); | 943 | Util.FireAndForget(DoSendCloudData, cloudDensity); |
927 | } | 944 | } |
928 | 945 | ||
929 | /// <summary> | 946 | /// <summary> |
@@ -1012,14 +1029,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1012 | agentData.child = false; | 1029 | agentData.child = false; |
1013 | agentData.firstname = m_firstName; | 1030 | agentData.firstname = m_firstName; |
1014 | agentData.lastname = m_lastName; | 1031 | agentData.lastname = m_lastName; |
1015 | 1032 | ||
1016 | ICapabilitiesModule capsModule = m_scene.RequestModuleInterface<ICapabilitiesModule>(); | 1033 | ICapabilitiesModule capsModule = m_scene.RequestModuleInterface<ICapabilitiesModule>(); |
1017 | 1034 | ||
1018 | if (capsModule == null) // can happen when shutting down. | 1035 | if (capsModule == null) // can happen when shutting down. |
1019 | return agentData; | 1036 | return agentData; |
1020 | 1037 | ||
1021 | agentData.CapsPath = capsModule.GetCapsPath(m_agentId); | 1038 | agentData.CapsPath = capsModule.GetCapsPath(m_agentId); |
1022 | agentData.ChildrenCapSeeds = new Dictionary<ulong,string>(capsModule.GetChildrenSeeds(m_agentId)); | 1039 | agentData.ChildrenCapSeeds = new Dictionary<ulong, string>(capsModule.GetChildrenSeeds(m_agentId)); |
1023 | 1040 | ||
1024 | return agentData; | 1041 | return agentData; |
1025 | } | 1042 | } |
@@ -1046,7 +1063,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1046 | newSimPack.RegionData.SimIP += (uint)byteIP[1] << 8; | 1063 | newSimPack.RegionData.SimIP += (uint)byteIP[1] << 8; |
1047 | newSimPack.RegionData.SimIP += (uint)byteIP[0]; | 1064 | newSimPack.RegionData.SimIP += (uint)byteIP[0]; |
1048 | newSimPack.RegionData.SimPort = (ushort)externalIPEndPoint.Port; | 1065 | newSimPack.RegionData.SimPort = (ushort)externalIPEndPoint.Port; |
1049 | newSimPack.RegionData.SeedCapability = Utils.StringToBytes(capsURL); | 1066 | newSimPack.RegionData.SeedCapability = Util.StringToBytes256(capsURL); |
1050 | 1067 | ||
1051 | // Hack to get this out immediately and skip throttles | 1068 | // Hack to get this out immediately and skip throttles |
1052 | OutPacket(newSimPack, ThrottleOutPacketType.Unknown); | 1069 | OutPacket(newSimPack, ThrottleOutPacketType.Unknown); |
@@ -1124,7 +1141,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1124 | teleport.Info.RegionHandle = regionHandle; | 1141 | teleport.Info.RegionHandle = regionHandle; |
1125 | teleport.Info.SimAccess = simAccess; | 1142 | teleport.Info.SimAccess = simAccess; |
1126 | 1143 | ||
1127 | teleport.Info.SeedCapability = Utils.StringToBytes(capsURL); | 1144 | teleport.Info.SeedCapability = Util.StringToBytes256(capsURL); |
1128 | 1145 | ||
1129 | IPAddress oIP = newRegionEndPoint.Address; | 1146 | IPAddress oIP = newRegionEndPoint.Address; |
1130 | byte[] byteIP = oIP.GetAddressBytes(); | 1147 | byte[] byteIP = oIP.GetAddressBytes(); |
@@ -1149,7 +1166,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1149 | { | 1166 | { |
1150 | TeleportFailedPacket tpFailed = (TeleportFailedPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFailed); | 1167 | TeleportFailedPacket tpFailed = (TeleportFailedPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFailed); |
1151 | tpFailed.Info.AgentID = AgentId; | 1168 | tpFailed.Info.AgentID = AgentId; |
1152 | tpFailed.Info.Reason = Utils.StringToBytes(reason); | 1169 | tpFailed.Info.Reason = Util.StringToBytes256(reason); |
1153 | tpFailed.AlertInfo = new TeleportFailedPacket.AlertInfoBlock[0]; | 1170 | tpFailed.AlertInfo = new TeleportFailedPacket.AlertInfoBlock[0]; |
1154 | 1171 | ||
1155 | // Hack to get this out immediately and skip throttles | 1172 | // Hack to get this out immediately and skip throttles |
@@ -1211,11 +1228,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1211 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); | 1228 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); |
1212 | pc.Header.Reliable = false; | 1229 | pc.Header.Reliable = false; |
1213 | 1230 | ||
1214 | OutgoingPacket oldestPacket = m_udpClient.NeedAcks.GetOldest(); | ||
1215 | |||
1216 | pc.PingID.PingID = seq; | 1231 | pc.PingID.PingID = seq; |
1217 | pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; | 1232 | // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit |
1218 | 1233 | pc.PingID.OldestUnacked = 0; | |
1234 | |||
1219 | OutPacket(pc, ThrottleOutPacketType.Unknown); | 1235 | OutPacket(pc, ThrottleOutPacketType.Unknown); |
1220 | } | 1236 | } |
1221 | 1237 | ||
@@ -1521,7 +1537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1521 | inventoryReply.Header.Zerocoded = true; | 1537 | inventoryReply.Header.Zerocoded = true; |
1522 | OutPacket(inventoryReply, ThrottleOutPacketType.Asset); | 1538 | OutPacket(inventoryReply, ThrottleOutPacketType.Asset); |
1523 | } | 1539 | } |
1524 | 1540 | ||
1525 | protected void SendBulkUpdateInventoryFolder(InventoryFolderBase folderBase) | 1541 | protected void SendBulkUpdateInventoryFolder(InventoryFolderBase folderBase) |
1526 | { | 1542 | { |
1527 | // We will use the same transaction id for all the separate packets to be sent out in this update. | 1543 | // We will use the same transaction id for all the separate packets to be sent out in this update. |
@@ -1545,7 +1561,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1545 | bulkUpdate.FolderData = folderDataBlocks.ToArray(); | 1561 | bulkUpdate.FolderData = folderDataBlocks.ToArray(); |
1546 | List<BulkUpdateInventoryPacket.ItemDataBlock> foo = new List<BulkUpdateInventoryPacket.ItemDataBlock>(); | 1562 | List<BulkUpdateInventoryPacket.ItemDataBlock> foo = new List<BulkUpdateInventoryPacket.ItemDataBlock>(); |
1547 | bulkUpdate.ItemData = foo.ToArray(); | 1563 | bulkUpdate.ItemData = foo.ToArray(); |
1548 | 1564 | ||
1549 | //m_log.Debug("SendBulkUpdateInventory :" + bulkUpdate); | 1565 | //m_log.Debug("SendBulkUpdateInventory :" + bulkUpdate); |
1550 | OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); | 1566 | OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); |
1551 | } | 1567 | } |
@@ -1668,7 +1684,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1668 | 1684 | ||
1669 | return itemBlock; | 1685 | return itemBlock; |
1670 | } | 1686 | } |
1671 | 1687 | ||
1672 | public void SendBulkUpdateInventory(InventoryNodeBase node) | 1688 | public void SendBulkUpdateInventory(InventoryNodeBase node) |
1673 | { | 1689 | { |
1674 | if (node is InventoryItemBase) | 1690 | if (node is InventoryItemBase) |
@@ -1678,7 +1694,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1678 | else | 1694 | else |
1679 | m_log.ErrorFormat("[CLIENT]: Client for {0} sent unknown inventory node named {1}", Name, node.Name); | 1695 | m_log.ErrorFormat("[CLIENT]: Client for {0} sent unknown inventory node named {1}", Name, node.Name); |
1680 | } | 1696 | } |
1681 | 1697 | ||
1682 | protected void SendBulkUpdateInventoryItem(InventoryItemBase item) | 1698 | protected void SendBulkUpdateInventoryItem(InventoryItemBase item) |
1683 | { | 1699 | { |
1684 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; | 1700 | const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; |
@@ -1881,11 +1897,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1881 | AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate); | 1897 | AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate); |
1882 | sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid; | 1898 | sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid; |
1883 | sendAgentDataUpdate.AgentData.AgentID = agentid; | 1899 | sendAgentDataUpdate.AgentData.AgentID = agentid; |
1884 | sendAgentDataUpdate.AgentData.FirstName = Utils.StringToBytes(firstname); | 1900 | sendAgentDataUpdate.AgentData.FirstName = Util.StringToBytes256(firstname); |
1885 | sendAgentDataUpdate.AgentData.GroupName = Utils.StringToBytes(groupname); | 1901 | sendAgentDataUpdate.AgentData.GroupName = Util.StringToBytes256(groupname); |
1886 | sendAgentDataUpdate.AgentData.GroupPowers = grouppowers; | 1902 | sendAgentDataUpdate.AgentData.GroupPowers = grouppowers; |
1887 | sendAgentDataUpdate.AgentData.GroupTitle = Utils.StringToBytes(grouptitle); | 1903 | sendAgentDataUpdate.AgentData.GroupTitle = Util.StringToBytes256(grouptitle); |
1888 | sendAgentDataUpdate.AgentData.LastName = Utils.StringToBytes(lastname); | 1904 | sendAgentDataUpdate.AgentData.LastName = Util.StringToBytes256(lastname); |
1889 | OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task); | 1905 | OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task); |
1890 | } | 1906 | } |
1891 | 1907 | ||
@@ -1898,7 +1914,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1898 | { | 1914 | { |
1899 | AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); | 1915 | AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); |
1900 | alertPack.AlertData = new AlertMessagePacket.AlertDataBlock(); | 1916 | alertPack.AlertData = new AlertMessagePacket.AlertDataBlock(); |
1901 | alertPack.AlertData.Message = Utils.StringToBytes(message); | 1917 | alertPack.AlertData.Message = Util.StringToBytes256(message); |
1902 | alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[0]; | 1918 | alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[0]; |
1903 | OutPacket(alertPack, ThrottleOutPacketType.Task); | 1919 | OutPacket(alertPack, ThrottleOutPacketType.Task); |
1904 | } | 1920 | } |
@@ -1925,7 +1941,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1925 | { | 1941 | { |
1926 | AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); | 1942 | AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); |
1927 | alertPack.AgentData.AgentID = AgentId; | 1943 | alertPack.AgentData.AgentID = AgentId; |
1928 | alertPack.AlertData.Message = Utils.StringToBytes(message); | 1944 | alertPack.AlertData.Message = Util.StringToBytes256(message); |
1929 | alertPack.AlertData.Modal = modal; | 1945 | alertPack.AlertData.Modal = modal; |
1930 | 1946 | ||
1931 | return alertPack; | 1947 | return alertPack; |
@@ -1935,12 +1951,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1935 | string url) | 1951 | string url) |
1936 | { | 1952 | { |
1937 | LoadURLPacket loadURL = (LoadURLPacket)PacketPool.Instance.GetPacket(PacketType.LoadURL); | 1953 | LoadURLPacket loadURL = (LoadURLPacket)PacketPool.Instance.GetPacket(PacketType.LoadURL); |
1938 | loadURL.Data.ObjectName = Utils.StringToBytes(objectname); | 1954 | loadURL.Data.ObjectName = Util.StringToBytes256(objectname); |
1939 | loadURL.Data.ObjectID = objectID; | 1955 | loadURL.Data.ObjectID = objectID; |
1940 | loadURL.Data.OwnerID = ownerID; | 1956 | loadURL.Data.OwnerID = ownerID; |
1941 | loadURL.Data.OwnerIsGroup = groupOwned; | 1957 | loadURL.Data.OwnerIsGroup = groupOwned; |
1942 | loadURL.Data.Message = Utils.StringToBytes(message); | 1958 | loadURL.Data.Message = Util.StringToBytes256(message); |
1943 | loadURL.Data.URL = Utils.StringToBytes(url); | 1959 | loadURL.Data.URL = Util.StringToBytes256(url); |
1944 | OutPacket(loadURL, ThrottleOutPacketType.Task); | 1960 | OutPacket(loadURL, ThrottleOutPacketType.Task); |
1945 | } | 1961 | } |
1946 | 1962 | ||
@@ -1948,18 +1964,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1948 | { | 1964 | { |
1949 | ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); | 1965 | ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); |
1950 | dialog.Data.ObjectID = objectID; | 1966 | dialog.Data.ObjectID = objectID; |
1951 | dialog.Data.ObjectName = Utils.StringToBytes(objectname); | 1967 | dialog.Data.ObjectName = Util.StringToBytes256(objectname); |
1952 | // this is the username of the *owner* | 1968 | // this is the username of the *owner* |
1953 | dialog.Data.FirstName = Utils.StringToBytes(ownerFirstName); | 1969 | dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); |
1954 | dialog.Data.LastName = Utils.StringToBytes(ownerLastName); | 1970 | dialog.Data.LastName = Util.StringToBytes256(ownerLastName); |
1955 | dialog.Data.Message = Utils.StringToBytes(msg); | 1971 | dialog.Data.Message = Util.StringToBytes1024(msg); |
1956 | dialog.Data.ImageID = textureID; | 1972 | dialog.Data.ImageID = textureID; |
1957 | dialog.Data.ChatChannel = ch; | 1973 | dialog.Data.ChatChannel = ch; |
1958 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; | 1974 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; |
1959 | for (int i = 0; i < buttonlabels.Length; i++) | 1975 | for (int i = 0; i < buttonlabels.Length; i++) |
1960 | { | 1976 | { |
1961 | buttons[i] = new ScriptDialogPacket.ButtonsBlock(); | 1977 | buttons[i] = new ScriptDialogPacket.ButtonsBlock(); |
1962 | buttons[i].ButtonLabel = Utils.StringToBytes(buttonlabels[i]); | 1978 | buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]); |
1963 | } | 1979 | } |
1964 | dialog.Buttons = buttons; | 1980 | dialog.Buttons = buttons; |
1965 | OutPacket(dialog, ThrottleOutPacketType.Task); | 1981 | OutPacket(dialog, ThrottleOutPacketType.Task); |
@@ -2115,19 +2131,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2115 | avatarReply.AgentData.AgentID = AgentId; | 2131 | avatarReply.AgentData.AgentID = AgentId; |
2116 | avatarReply.AgentData.AvatarID = avatarID; | 2132 | avatarReply.AgentData.AvatarID = avatarID; |
2117 | if (aboutText != null) | 2133 | if (aboutText != null) |
2118 | avatarReply.PropertiesData.AboutText = Utils.StringToBytes(aboutText); | 2134 | avatarReply.PropertiesData.AboutText = Util.StringToBytes1024(aboutText); |
2119 | else | 2135 | else |
2120 | avatarReply.PropertiesData.AboutText = Utils.StringToBytes(""); | 2136 | avatarReply.PropertiesData.AboutText = Utils.EmptyBytes; |
2121 | avatarReply.PropertiesData.BornOn = Utils.StringToBytes(bornOn); | 2137 | avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn); |
2122 | avatarReply.PropertiesData.CharterMember = charterMember; | 2138 | avatarReply.PropertiesData.CharterMember = charterMember; |
2123 | if (flAbout != null) | 2139 | if (flAbout != null) |
2124 | avatarReply.PropertiesData.FLAboutText = Utils.StringToBytes(flAbout); | 2140 | avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout); |
2125 | else | 2141 | else |
2126 | avatarReply.PropertiesData.FLAboutText = Utils.StringToBytes(""); | 2142 | avatarReply.PropertiesData.FLAboutText = Utils.EmptyBytes; |
2127 | avatarReply.PropertiesData.Flags = flags; | 2143 | avatarReply.PropertiesData.Flags = flags; |
2128 | avatarReply.PropertiesData.FLImageID = flImageID; | 2144 | avatarReply.PropertiesData.FLImageID = flImageID; |
2129 | avatarReply.PropertiesData.ImageID = imageID; | 2145 | avatarReply.PropertiesData.ImageID = imageID; |
2130 | avatarReply.PropertiesData.ProfileURL = Utils.StringToBytes(profileURL); | 2146 | avatarReply.PropertiesData.ProfileURL = Util.StringToBytes256(profileURL); |
2131 | avatarReply.PropertiesData.PartnerID = partnerID; | 2147 | avatarReply.PropertiesData.PartnerID = partnerID; |
2132 | OutPacket(avatarReply, ThrottleOutPacketType.Task); | 2148 | OutPacket(avatarReply, ThrottleOutPacketType.Task); |
2133 | } | 2149 | } |
@@ -2254,7 +2270,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2254 | Group.Contribution = GroupMembership[i].Contribution; | 2270 | Group.Contribution = GroupMembership[i].Contribution; |
2255 | Group.GroupID = GroupMembership[i].GroupID; | 2271 | Group.GroupID = GroupMembership[i].GroupID; |
2256 | Group.GroupInsigniaID = GroupMembership[i].GroupPicture; | 2272 | Group.GroupInsigniaID = GroupMembership[i].GroupPicture; |
2257 | Group.GroupName = Utils.StringToBytes(GroupMembership[i].GroupName); | 2273 | Group.GroupName = Util.StringToBytes256(GroupMembership[i].GroupName); |
2258 | Group.GroupPowers = GroupMembership[i].GroupPowers; | 2274 | Group.GroupPowers = GroupMembership[i].GroupPowers; |
2259 | Groups[i] = Group; | 2275 | Groups[i] = Group; |
2260 | 2276 | ||
@@ -2288,7 +2304,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2288 | UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] uidnameblock = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock[1]; | 2304 | UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] uidnameblock = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock[1]; |
2289 | UUIDGroupNameReplyPacket.UUIDNameBlockBlock uidnamebloc = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock(); | 2305 | UUIDGroupNameReplyPacket.UUIDNameBlockBlock uidnamebloc = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock(); |
2290 | uidnamebloc.ID = groupLLUID; | 2306 | uidnamebloc.ID = groupLLUID; |
2291 | uidnamebloc.GroupName = Utils.StringToBytes(GroupName); | 2307 | uidnamebloc.GroupName = Util.StringToBytes256(GroupName); |
2292 | uidnameblock[0] = uidnamebloc; | 2308 | uidnameblock[0] = uidnamebloc; |
2293 | pack.UUIDNameBlock = uidnameblock; | 2309 | pack.UUIDNameBlock = uidnameblock; |
2294 | OutPacket(pack, ThrottleOutPacketType.Task); | 2310 | OutPacket(pack, ThrottleOutPacketType.Task); |
@@ -2313,8 +2329,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2313 | lsrepdb.Score = lsrpia[i].Score; | 2329 | lsrepdb.Score = lsrpia[i].Score; |
2314 | lsrepdb.TaskID = lsrpia[i].TaskID; | 2330 | lsrepdb.TaskID = lsrpia[i].TaskID; |
2315 | lsrepdb.TaskLocalID = lsrpia[i].TaskLocalID; | 2331 | lsrepdb.TaskLocalID = lsrpia[i].TaskLocalID; |
2316 | lsrepdb.TaskName = Utils.StringToBytes(lsrpia[i].TaskName); | 2332 | lsrepdb.TaskName = Util.StringToBytes256(lsrpia[i].TaskName); |
2317 | lsrepdb.OwnerName = Utils.StringToBytes(lsrpia[i].OwnerName); | 2333 | lsrepdb.OwnerName = Util.StringToBytes256(lsrpia[i].OwnerName); |
2318 | lsrepdba[i] = lsrepdb; | 2334 | lsrepdba[i] = lsrepdb; |
2319 | } | 2335 | } |
2320 | lsrp.ReportData = lsrepdba; | 2336 | lsrp.ReportData = lsrepdba; |
@@ -3102,9 +3118,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3102 | awb.ItemID = wearables[i].ItemID; | 3118 | awb.ItemID = wearables[i].ItemID; |
3103 | aw.WearableData[i] = awb; | 3119 | aw.WearableData[i] = awb; |
3104 | 3120 | ||
3105 | // m_log.DebugFormat( | 3121 | // m_log.DebugFormat( |
3106 | // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", | 3122 | // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", |
3107 | // awb.ItemID, awb.AssetID, i, Name); | 3123 | // awb.ItemID, awb.AssetID, i, Name); |
3108 | } | 3124 | } |
3109 | 3125 | ||
3110 | OutPacket(aw, ThrottleOutPacketType.Task); | 3126 | OutPacket(aw, ThrottleOutPacketType.Task); |
@@ -3127,7 +3143,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3127 | 3143 | ||
3128 | avp.Sender.IsTrial = false; | 3144 | avp.Sender.IsTrial = false; |
3129 | avp.Sender.ID = agentID; | 3145 | avp.Sender.ID = agentID; |
3130 | OutPacket(avp, ThrottleOutPacketType.State); | 3146 | OutPacket(avp, ThrottleOutPacketType.Task); |
3131 | } | 3147 | } |
3132 | 3148 | ||
3133 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3149 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3159,123 +3175,174 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3159 | 3175 | ||
3160 | #endregion | 3176 | #endregion |
3161 | 3177 | ||
3162 | #region Avatar Packet/data sending Methods | 3178 | #region Prim/Avatar Updates |
3163 | 3179 | ||
3164 | /// <summary> | 3180 | /*void SendObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) |
3165 | /// send a objectupdate packet with information about the clients avatar | ||
3166 | /// </summary> | ||
3167 | public void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, | ||
3168 | uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) | ||
3169 | { | 3181 | { |
3170 | ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | 3182 | bool canUseCompressed, canUseImproved; |
3171 | // TODO: don't create new blocks if recycling an old packet | 3183 | UpdateFlagsToPacketType(creatorFlags, updateFlags, out canUseCompressed, out canUseImproved); |
3172 | objupdate.RegionData.RegionHandle = regionHandle; | 3184 | |
3173 | objupdate.RegionData.TimeDilation = ushort.MaxValue; | 3185 | if (!canUseImproved && !canUseCompressed) |
3174 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | 3186 | SendFullObjectUpdate(obj, creatorFlags, updateFlags); |
3175 | objupdate.ObjectData[0] = CreateDefaultAvatarPacket(textureEntry); | 3187 | else if (!canUseImproved) |
3188 | SendObjectUpdateCompressed(obj, creatorFlags, updateFlags); | ||
3189 | else | ||
3190 | SendImprovedTerseObjectUpdate(obj, creatorFlags, updateFlags); | ||
3191 | } | ||
3176 | 3192 | ||
3177 | //give this avatar object a local id and assign the user a name | 3193 | void SendFullObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) |
3178 | objupdate.ObjectData[0].ID = avatarLocalID; | 3194 | { |
3179 | objupdate.ObjectData[0].FullID = avatarID; | 3195 | IClientAPI owner; |
3180 | objupdate.ObjectData[0].ParentID = parentID; | 3196 | if (m_scene.ClientManager.TryGetValue(obj.OwnerID, out owner) && owner is LLClientView) |
3181 | objupdate.ObjectData[0].NameValue = | 3197 | { |
3182 | Utils.StringToBytes("FirstName STRING RW SV " + firstName + "\nLastName STRING RW SV " + lastName + "\nTitle STRING RW SV " + grouptitle); | 3198 | LLClientView llOwner = (LLClientView)owner; |
3183 | 3199 | ||
3184 | Vector3 pos2 = new Vector3(Pos.X, Pos.Y, Pos.Z); | 3200 | // Send an update out to the owner |
3185 | byte[] pb = pos2.GetBytes(); | 3201 | ObjectUpdatePacket updateToOwner = new ObjectUpdatePacket(); |
3186 | Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); | 3202 | updateToOwner.RegionData.RegionHandle = obj.RegionHandle; |
3203 | //updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); | ||
3204 | updateToOwner.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
3205 | updateToOwner.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags | creatorFlags | PrimFlags.ObjectYouOwner, 0); | ||
3187 | 3206 | ||
3188 | byte[] rot = rotation.GetBytes(); | 3207 | m_udpServer.SendPacket(llOwner.UDPClient, updateToOwner, ThrottleOutPacketType.State, true); |
3189 | Array.Copy(rot, 0, objupdate.ObjectData[0].ObjectData, 52, rot.Length); | 3208 | } |
3190 | 3209 | ||
3191 | objupdate.Header.Zerocoded = true; | 3210 | // Send an update out to everyone else |
3192 | OutPacket(objupdate, ThrottleOutPacketType.Task); | 3211 | ObjectUpdatePacket updateToOthers = new ObjectUpdatePacket(); |
3212 | updateToOthers.RegionData.RegionHandle = obj.RegionHandle; | ||
3213 | //updateToOthers.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); | ||
3214 | updateToOthers.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
3215 | updateToOthers.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags, 0); | ||
3216 | |||
3217 | m_scene.ClientManager.ForEach( | ||
3218 | delegate(IClientAPI client) | ||
3219 | { | ||
3220 | if (client.AgentId != obj.OwnerID && client is LLClientView) | ||
3221 | { | ||
3222 | LLClientView llClient = (LLClientView)client; | ||
3223 | m_udpServer.SendPacket(llClient.UDPClient, updateToOthers, ThrottleOutPacketType.State, true); | ||
3224 | } | ||
3225 | } | ||
3226 | ); | ||
3193 | } | 3227 | } |
3194 | 3228 | ||
3195 | /// <summary> | 3229 | void SendObjectUpdateCompressed(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) |
3196 | /// Send a terse positional/rotation/velocity update about an avatar | ||
3197 | /// to the client. This avatar can be that of the client itself. | ||
3198 | /// </summary> | ||
3199 | public virtual void SendAvatarTerseUpdate(ulong regionHandle, | ||
3200 | ushort timeDilation, uint localID, Vector3 position, | ||
3201 | Vector3 velocity, Quaternion rotation, UUID agentid) | ||
3202 | { | 3230 | { |
3203 | if (rotation.X == rotation.Y && | 3231 | } |
3204 | rotation.Y == rotation.Z && | ||
3205 | rotation.Z == rotation.W && rotation.W == 0) | ||
3206 | rotation = Quaternion.Identity; | ||
3207 | 3232 | ||
3208 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = | 3233 | void SendImprovedTerseObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) |
3209 | CreateAvatarImprovedBlock(localID, position, velocity,rotation); | 3234 | { |
3210 | 3235 | } | |
3211 | lock (m_avatarTerseUpdates) | 3236 | |
3212 | { | 3237 | void UpdateFlagsToPacketType(PrimFlags creatorFlags, PrimUpdateFlags updateFlags, out bool canUseCompressed, out bool canUseImproved) |
3213 | m_avatarTerseUpdates.Add(terseBlock); | 3238 | { |
3239 | canUseCompressed = true; | ||
3240 | canUseImproved = true; | ||
3214 | 3241 | ||
3215 | // If packet is full or own movement packet, send it. | 3242 | if ((updateFlags & PrimUpdateFlags.FullUpdate) == PrimUpdateFlags.FullUpdate || creatorFlags != PrimFlags.None) |
3216 | if (m_avatarTerseUpdates.Count >= m_avatarTerseUpdatesPerPacket) | 3243 | { |
3244 | canUseCompressed = false; | ||
3245 | canUseImproved = false; | ||
3246 | } | ||
3247 | else | ||
3248 | { | ||
3249 | if ((updateFlags & PrimUpdateFlags.Velocity) != 0 || | ||
3250 | (updateFlags & PrimUpdateFlags.Acceleration) != 0 || | ||
3251 | (updateFlags & PrimUpdateFlags.CollisionPlane) != 0 || | ||
3252 | (updateFlags & PrimUpdateFlags.Joint) != 0) | ||
3217 | { | 3253 | { |
3218 | ProcessAvatarTerseUpdates(this, null); | 3254 | canUseCompressed = false; |
3219 | } | 3255 | } |
3220 | else if (m_avatarTerseUpdates.Count == 1) | 3256 | |
3257 | if ((updateFlags & PrimUpdateFlags.PrimFlags) != 0 || | ||
3258 | (updateFlags & PrimUpdateFlags.ParentID) != 0 || | ||
3259 | (updateFlags & PrimUpdateFlags.Scale) != 0 || | ||
3260 | (updateFlags & PrimUpdateFlags.PrimData) != 0 || | ||
3261 | (updateFlags & PrimUpdateFlags.Text) != 0 || | ||
3262 | (updateFlags & PrimUpdateFlags.NameValue) != 0 || | ||
3263 | (updateFlags & PrimUpdateFlags.ExtraData) != 0 || | ||
3264 | (updateFlags & PrimUpdateFlags.TextureAnim) != 0 || | ||
3265 | (updateFlags & PrimUpdateFlags.Sound) != 0 || | ||
3266 | (updateFlags & PrimUpdateFlags.Particles) != 0 || | ||
3267 | (updateFlags & PrimUpdateFlags.Material) != 0 || | ||
3268 | (updateFlags & PrimUpdateFlags.ClickAction) != 0 || | ||
3269 | (updateFlags & PrimUpdateFlags.MediaURL) != 0 || | ||
3270 | (updateFlags & PrimUpdateFlags.Joint) != 0) | ||
3221 | { | 3271 | { |
3222 | lock (m_avatarTerseUpdateTimer) | 3272 | canUseImproved = false; |
3223 | m_avatarTerseUpdateTimer.Start(); | ||
3224 | } | 3273 | } |
3225 | } | 3274 | } |
3226 | } | 3275 | }*/ |
3276 | |||
3277 | #endregion Prim/Avatar Updates | ||
3227 | 3278 | ||
3228 | private void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) | 3279 | #region Avatar Packet/Data Sending Methods |
3280 | |||
3281 | /// <summary> | ||
3282 | /// Send an ObjectUpdate packet with information about an avatar | ||
3283 | /// </summary> | ||
3284 | public void SendAvatarData(SendAvatarData data) | ||
3229 | { | 3285 | { |
3230 | lock (m_avatarTerseUpdates) | 3286 | ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); |
3231 | { | 3287 | objupdate.Header.Zerocoded = true; |
3232 | ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | ||
3233 | 3288 | ||
3234 | terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock(); | 3289 | objupdate.RegionData.RegionHandle = data.RegionHandle; |
3290 | objupdate.RegionData.TimeDilation = ushort.MaxValue; | ||
3235 | 3291 | ||
3236 | terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; | 3292 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; |
3237 | terse.RegionData.TimeDilation = | 3293 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data); |
3238 | (ushort)(Scene.TimeDilation * ushort.MaxValue); | ||
3239 | 3294 | ||
3240 | int max = m_avatarTerseUpdatesPerPacket; | 3295 | OutPacket(objupdate, ThrottleOutPacketType.Task); |
3241 | if (max > m_avatarTerseUpdates.Count) | 3296 | } |
3242 | max = m_avatarTerseUpdates.Count; | ||
3243 | 3297 | ||
3244 | int count = 0; | 3298 | /// <summary> |
3245 | int size = 0; | 3299 | /// Send a terse positional/rotation/velocity update about an avatar |
3300 | /// to the client. This avatar can be that of the client itself. | ||
3301 | /// </summary> | ||
3302 | public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) | ||
3303 | { | ||
3304 | if (data.Priority == double.NaN) | ||
3305 | { | ||
3306 | m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update"); | ||
3307 | return; | ||
3308 | } | ||
3246 | 3309 | ||
3247 | byte[] zerobuffer = new byte[1024]; | 3310 | Quaternion rotation = data.Rotation; |
3248 | byte[] blockbuffer = new byte[1024]; | 3311 | if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) |
3312 | rotation = Quaternion.Identity; | ||
3249 | 3313 | ||
3250 | for (count = 0 ; count < max ; count++) | 3314 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateImprovedTerseBlock(data); |
3251 | { | ||
3252 | int length = 0; | ||
3253 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); | ||
3254 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | ||
3255 | if (size + length > Packet.MTU) | ||
3256 | break; | ||
3257 | size += length; | ||
3258 | } | ||
3259 | 3315 | ||
3260 | terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; | 3316 | lock (m_avatarTerseUpdates.SyncRoot) |
3317 | m_avatarTerseUpdates.Enqueue(data.Priority, terseBlock, data.LocalID); | ||
3261 | 3318 | ||
3262 | for (int i = 0 ; i < count ; i++) | 3319 | // If we received an update about our own avatar, process the avatar update priority queue immediately |
3263 | { | 3320 | if (data.AgentID == m_agentId) |
3264 | terse.ObjectData[i] = m_avatarTerseUpdates[0]; | 3321 | ProcessAvatarTerseUpdates(); |
3265 | m_avatarTerseUpdates.RemoveAt(0); | 3322 | } |
3266 | } | ||
3267 | 3323 | ||
3268 | terse.Header.Reliable = false; | 3324 | private void ProcessAvatarTerseUpdates() |
3269 | terse.Header.Zerocoded = true; | 3325 | { |
3270 | // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed | 3326 | ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); |
3271 | OutPacket(terse, ThrottleOutPacketType.Task); | 3327 | terse.Header.Reliable = false; |
3328 | terse.Header.Zerocoded = true; | ||
3272 | 3329 | ||
3273 | if (m_avatarTerseUpdates.Count == 0) | 3330 | //terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock(); |
3274 | { | 3331 | terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; |
3275 | lock (m_avatarTerseUpdateTimer) | 3332 | terse.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); |
3276 | m_avatarTerseUpdateTimer.Stop(); | 3333 | |
3277 | } | 3334 | lock (m_avatarTerseUpdates.SyncRoot) |
3335 | { | ||
3336 | int count = Math.Min(m_avatarTerseUpdates.Count, m_avatarTerseUpdatesPerPacket); | ||
3337 | if (count == 0) | ||
3338 | return; | ||
3339 | |||
3340 | terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; | ||
3341 | for (int i = 0; i < count; i++) | ||
3342 | terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue(); | ||
3278 | } | 3343 | } |
3344 | |||
3345 | OutPacket(terse, ThrottleOutPacketType.Task); | ||
3279 | } | 3346 | } |
3280 | 3347 | ||
3281 | public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) | 3348 | public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) |
@@ -3294,7 +3361,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3294 | { | 3361 | { |
3295 | CoarseLocationUpdatePacket.LocationBlock lb = | 3362 | CoarseLocationUpdatePacket.LocationBlock lb = |
3296 | new CoarseLocationUpdatePacket.LocationBlock(); | 3363 | new CoarseLocationUpdatePacket.LocationBlock(); |
3297 | 3364 | ||
3298 | lb.X = (byte)CoarseLocations[i].X; | 3365 | lb.X = (byte)CoarseLocations[i].X; |
3299 | lb.Y = (byte)CoarseLocations[i].Y; | 3366 | lb.Y = (byte)CoarseLocations[i].Y; |
3300 | 3367 | ||
@@ -3314,319 +3381,211 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3314 | OutPacket(loc, ThrottleOutPacketType.Task); | 3381 | OutPacket(loc, ThrottleOutPacketType.Task); |
3315 | } | 3382 | } |
3316 | 3383 | ||
3317 | #endregion | 3384 | #endregion Avatar Packet/Data Sending Methods |
3318 | 3385 | ||
3319 | #region Primitive Packet/data Sending Methods | 3386 | #region Primitive Packet/Data Sending Methods |
3320 | 3387 | ||
3321 | /// <summary> | 3388 | public void SendPrimitiveToClient(SendPrimitiveData data) |
3322 | /// | ||
3323 | /// </summary> | ||
3324 | /// <param name="localID"></param> | ||
3325 | /// <param name="rotation"></param> | ||
3326 | /// <param name="attachPoint"></param> | ||
3327 | public void AttachObject(uint localID, Quaternion rotation, byte attachPoint, UUID ownerID) | ||
3328 | { | 3389 | { |
3329 | if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD | 3390 | if (data.priority == double.NaN) |
3391 | { | ||
3392 | m_log.Error("[LLClientView] SendPrimitiveToClient received a NaN priority, dropping update"); | ||
3330 | return; | 3393 | return; |
3394 | } | ||
3331 | 3395 | ||
3332 | ObjectAttachPacket attach = (ObjectAttachPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAttach); | 3396 | Quaternion rotation = data.rotation; |
3333 | // TODO: don't create new blocks if recycling an old packet | 3397 | if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) |
3334 | attach.AgentData.AgentID = AgentId; | 3398 | rotation = Quaternion.Identity; |
3335 | attach.AgentData.SessionID = m_sessionId; | ||
3336 | attach.AgentData.AttachmentPoint = attachPoint; | ||
3337 | attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; | ||
3338 | attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); | ||
3339 | attach.ObjectData[0].ObjectLocalID = localID; | ||
3340 | attach.ObjectData[0].Rotation = rotation; | ||
3341 | attach.Header.Zerocoded = true; | ||
3342 | OutPacket(attach, ThrottleOutPacketType.Task); | ||
3343 | } | ||
3344 | |||
3345 | public void SendPrimitiveToClient( | ||
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 | { | ||
3351 | byte[] textureanim = new byte[0]; | ||
3352 | |||
3353 | SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, vel, | ||
3354 | acc, rotation, rvel, flags, | ||
3355 | objectID, ownerID, text, color, parentID, particleSystem, | ||
3356 | clickAction, material, textureanim, false, 0, UUID.Zero, UUID.Zero, 0, 0, 0); | ||
3357 | } | ||
3358 | |||
3359 | public void SendPrimitiveToClient( | ||
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 | 3399 | ||
3367 | if (AttachPoint > 30 && ownerID != AgentId) // Someone else's HUD | 3400 | if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD |
3368 | return; | 3401 | return; |
3369 | if (primShape.PCode == 9 && primShape.State != 0 && parentID == 0) | 3402 | if (data.primShape.State != 0 && data.parentID == 0 && data.primShape.PCode == 9) |
3370 | return; | 3403 | return; |
3371 | 3404 | ||
3372 | if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) | 3405 | ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data); |
3373 | rotation = Quaternion.Identity; | ||
3374 | 3406 | ||
3375 | ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(primShape, flags); | 3407 | lock (m_primFullUpdates.SyncRoot) |
3408 | m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); | ||
3409 | } | ||
3376 | 3410 | ||
3377 | objectData.ID = localID; | 3411 | void ProcessPrimFullUpdates() |
3378 | objectData.FullID = objectID; | 3412 | { |
3379 | objectData.OwnerID = ownerID; | 3413 | ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); |
3414 | outPacket.Header.Zerocoded = true; | ||
3380 | 3415 | ||
3381 | objectData.Text = Util.StringToBytes256(text); | 3416 | outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; |
3382 | objectData.TextColor[0] = color[0]; | 3417 | outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); |
3383 | objectData.TextColor[1] = color[1]; | ||
3384 | objectData.TextColor[2] = color[2]; | ||
3385 | objectData.TextColor[3] = color[3]; | ||
3386 | objectData.ParentID = parentID; | ||
3387 | objectData.PSBlock = particleSystem; | ||
3388 | objectData.ClickAction = clickAction; | ||
3389 | objectData.Material = material; | ||
3390 | objectData.Flags = 0; | ||
3391 | 3418 | ||
3392 | if (attachment) | 3419 | lock (m_primFullUpdates.SyncRoot) |
3393 | { | 3420 | { |
3394 | // Necessary??? | 3421 | int count = Math.Min(m_primFullUpdates.Count, m_primFullUpdatesPerPacket); |
3395 | objectData.JointAxisOrAnchor = new Vector3(0, 0, 2); | 3422 | if (count == 0) |
3396 | objectData.JointPivot = new Vector3(0, 0, 0); | 3423 | return; |
3397 | |||
3398 | // Item from inventory??? | ||
3399 | objectData.NameValue = | ||
3400 | Utils.StringToBytes("AttachItemID STRING RW SV " + AssetId.Guid); | ||
3401 | objectData.State = (byte)((AttachPoint % 16) * 16 + (AttachPoint / 16)); | ||
3402 | } | ||
3403 | 3424 | ||
3404 | // Xantor 20080528: Send sound info as well | 3425 | outPacket.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[count]; |
3405 | // Xantor 20080530: Zero out everything if there's no SoundId, so zerocompression will work again | 3426 | for (int i = 0; i < count; i++) |
3406 | objectData.Sound = SoundId; | 3427 | outPacket.ObjectData[i] = m_primFullUpdates.Dequeue(); |
3407 | if (SoundId == UUID.Zero) | ||
3408 | { | ||
3409 | objectData.OwnerID = UUID.Zero; | ||
3410 | objectData.Gain = 0.0f; | ||
3411 | objectData.Radius = 0.0f; | ||
3412 | objectData.Flags = 0; | ||
3413 | } | ||
3414 | else | ||
3415 | { | ||
3416 | objectData.OwnerID = ownerID; | ||
3417 | objectData.Gain = (float)SoundGain; | ||
3418 | objectData.Radius = (float)SoundRadius; | ||
3419 | objectData.Flags = SoundFlags; | ||
3420 | } | 3428 | } |
3421 | 3429 | ||
3422 | byte[] pb = pos.GetBytes(); | 3430 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3423 | Array.Copy(pb, 0, objectData.ObjectData, 0, pb.Length); | 3431 | } |
3424 | |||
3425 | byte[] vel = velocity.GetBytes(); | ||
3426 | Array.Copy(vel, 0, objectData.ObjectData, pb.Length, vel.Length); | ||
3427 | |||
3428 | byte[] rot = rotation.GetBytes(); | ||
3429 | Array.Copy(rot, 0, objectData.ObjectData, 36, rot.Length); | ||
3430 | |||
3431 | byte[] rvel = rotational_velocity.GetBytes(); | ||
3432 | Array.Copy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length); | ||
3433 | 3432 | ||
3434 | if (textureanim.Length > 0) | 3433 | public void SendPrimTerseUpdate(SendPrimitiveTerseData data) |
3434 | { | ||
3435 | if (data.Priority == double.NaN) | ||
3435 | { | 3436 | { |
3436 | objectData.TextureAnim = textureanim; | 3437 | m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update"); |
3438 | return; | ||
3437 | } | 3439 | } |
3438 | 3440 | ||
3439 | lock (m_primFullUpdates) | 3441 | Quaternion rotation = data.Rotation; |
3440 | { | 3442 | if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) |
3441 | if (m_primFullUpdates.Count == 0) | 3443 | rotation = Quaternion.Identity; |
3442 | m_primFullUpdateTimer.Start(); | ||
3443 | 3444 | ||
3444 | m_primFullUpdates.Add(objectData); | 3445 | if (data.AttachPoint > 30 && data.OwnerID != AgentId) // Someone else's HUD |
3446 | return; | ||
3445 | 3447 | ||
3446 | if (m_primFullUpdates.Count >= m_primFullUpdatesPerPacket) | 3448 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = CreateImprovedTerseBlock(data); |
3447 | ProcessPrimFullUpdates(this, null); | ||
3448 | } | ||
3449 | } | ||
3450 | 3449 | ||
3451 | void HandleQueueEmpty(ThrottleOutPacketType queue) | 3450 | lock (m_primTerseUpdates.SyncRoot) |
3452 | { | 3451 | m_primTerseUpdates.Enqueue(data.Priority, objectData, data.LocalID); |
3453 | switch (queue) | ||
3454 | { | ||
3455 | case ThrottleOutPacketType.Texture: | ||
3456 | ProcessTextureRequests(); | ||
3457 | break; | ||
3458 | } | ||
3459 | } | 3452 | } |
3460 | 3453 | ||
3461 | void ProcessTextureRequests() | 3454 | void ProcessPrimTerseUpdates() |
3462 | { | 3455 | { |
3463 | if (m_imageManager != null) | 3456 | ImprovedTerseObjectUpdatePacket outPacket = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); |
3464 | m_imageManager.ProcessImageQueue(m_textureSendLimit); | 3457 | outPacket.Header.Reliable = false; |
3465 | } | 3458 | outPacket.Header.Zerocoded = true; |
3466 | 3459 | ||
3467 | void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) | 3460 | outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; |
3468 | { | 3461 | outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); |
3469 | lock (m_primFullUpdates) | ||
3470 | { | ||
3471 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | ||
3472 | { | ||
3473 | lock (m_primFullUpdateTimer) | ||
3474 | m_primFullUpdateTimer.Stop(); | ||
3475 | 3462 | ||
3463 | lock (m_primTerseUpdates.SyncRoot) | ||
3464 | { | ||
3465 | int count = Math.Min(m_primTerseUpdates.Count, m_primTerseUpdatesPerPacket); | ||
3466 | if (count == 0) | ||
3476 | return; | 3467 | return; |
3477 | } | ||
3478 | |||
3479 | ObjectUpdatePacket outPacket = | ||
3480 | (ObjectUpdatePacket)PacketPool.Instance.GetPacket( | ||
3481 | PacketType.ObjectUpdate); | ||
3482 | 3468 | ||
3483 | outPacket.RegionData.RegionHandle = | 3469 | outPacket.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; |
3484 | Scene.RegionInfo.RegionHandle; | 3470 | for (int i = 0; i < count; i++) |
3485 | outPacket.RegionData.TimeDilation = | 3471 | outPacket.ObjectData[i] = m_primTerseUpdates.Dequeue(); |
3486 | (ushort)(Scene.TimeDilation * ushort.MaxValue); | 3472 | } |
3487 | |||
3488 | int max = m_primFullUpdates.Count; | ||
3489 | if (max > m_primFullUpdatesPerPacket) | ||
3490 | max = m_primFullUpdatesPerPacket; | ||
3491 | |||
3492 | int count = 0; | ||
3493 | int size = 0; | ||
3494 | 3473 | ||
3495 | byte[] zerobuffer = new byte[1024]; | 3474 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3496 | byte[] blockbuffer = new byte[1024]; | 3475 | } |
3497 | 3476 | ||
3498 | for (count = 0 ; count < max ; count++) | 3477 | public void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) |
3478 | { | ||
3479 | PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler terse_update_priority_handler = | ||
3480 | delegate(ref double priority, uint local_id) | ||
3499 | { | 3481 | { |
3500 | int length = 0; | 3482 | priority = handler(new UpdatePriorityData(priority, local_id)); |
3501 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); | 3483 | return priority != double.NaN; |
3502 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | 3484 | }; |
3503 | if (size + length > Packet.MTU) | 3485 | PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler update_priority_handler = |
3504 | break; | 3486 | delegate(ref double priority, uint local_id) |
3505 | size += length; | 3487 | { |
3506 | } | 3488 | priority = handler(new UpdatePriorityData(priority, local_id)); |
3489 | return priority != double.NaN; | ||
3490 | }; | ||
3507 | 3491 | ||
3508 | outPacket.ObjectData = | 3492 | if ((type & StateUpdateTypes.AvatarTerse) != 0) |
3509 | new ObjectUpdatePacket.ObjectDataBlock[count]; | 3493 | { |
3494 | lock (m_avatarTerseUpdates.SyncRoot) | ||
3495 | m_avatarTerseUpdates.Reprioritize(terse_update_priority_handler); | ||
3496 | } | ||
3510 | 3497 | ||
3511 | for (int index = 0 ; index < count ; index++) | 3498 | if ((type & StateUpdateTypes.PrimitiveFull) != 0) |
3512 | { | 3499 | { |
3513 | outPacket.ObjectData[index] = m_primFullUpdates[0]; | 3500 | lock (m_primFullUpdates.SyncRoot) |
3514 | m_primFullUpdates.RemoveAt(0); | 3501 | m_primFullUpdates.Reprioritize(update_priority_handler); |
3515 | } | 3502 | } |
3516 | 3503 | ||
3517 | outPacket.Header.Zerocoded = true; | 3504 | if ((type & StateUpdateTypes.PrimitiveTerse) != 0) |
3518 | OutPacket(outPacket, ThrottleOutPacketType.State); | 3505 | { |
3506 | lock (m_primTerseUpdates.SyncRoot) | ||
3507 | m_primTerseUpdates.Reprioritize(terse_update_priority_handler); | ||
3508 | } | ||
3509 | } | ||
3519 | 3510 | ||
3520 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | 3511 | public void FlushPrimUpdates() |
3521 | lock (m_primFullUpdateTimer) | 3512 | { |
3522 | m_primFullUpdateTimer.Stop(); | 3513 | while (m_primFullUpdates.Count > 0) |
3514 | { | ||
3515 | ProcessPrimFullUpdates(); | ||
3516 | } | ||
3517 | while (m_primTerseUpdates.Count > 0) | ||
3518 | { | ||
3519 | ProcessPrimTerseUpdates(); | ||
3520 | } | ||
3521 | while (m_avatarTerseUpdates.Count > 0) | ||
3522 | { | ||
3523 | ProcessAvatarTerseUpdates(); | ||
3523 | } | 3524 | } |
3524 | } | 3525 | } |
3525 | 3526 | ||
3527 | #endregion Primitive Packet/Data Sending Methods | ||
3528 | |||
3526 | /// <summary> | 3529 | /// <summary> |
3527 | /// | 3530 | /// |
3528 | /// </summary> | 3531 | /// </summary> |
3529 | public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, | 3532 | /// <param name="localID"></param> |
3530 | Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) | 3533 | /// <param name="rotation"></param> |
3534 | /// <param name="attachPoint"></param> | ||
3535 | public void AttachObject(uint localID, Quaternion rotation, byte attachPoint, UUID ownerID) | ||
3531 | { | 3536 | { |
3532 | if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD | 3537 | if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD |
3533 | return; | 3538 | return; |
3534 | 3539 | ||
3535 | if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) | 3540 | ObjectAttachPacket attach = (ObjectAttachPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAttach); |
3536 | rotation = Quaternion.Identity; | 3541 | // TODO: don't create new blocks if recycling an old packet |
3537 | 3542 | attach.AgentData.AgentID = AgentId; | |
3538 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = | 3543 | attach.AgentData.SessionID = m_sessionId; |
3539 | CreatePrimImprovedBlock(localID, position, rotation, | 3544 | attach.AgentData.AttachmentPoint = attachPoint; |
3540 | velocity, rotationalvelocity, state); | 3545 | attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; |
3541 | 3546 | attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); | |
3542 | lock (m_primTerseUpdates) | 3547 | attach.ObjectData[0].ObjectLocalID = localID; |
3543 | { | 3548 | attach.ObjectData[0].Rotation = rotation; |
3544 | if (m_primTerseUpdates.Count == 0) | 3549 | attach.Header.Zerocoded = true; |
3545 | m_primTerseUpdateTimer.Start(); | 3550 | OutPacket(attach, ThrottleOutPacketType.Task); |
3546 | |||
3547 | m_primTerseUpdates.Add(objectData); | ||
3548 | |||
3549 | if (m_primTerseUpdates.Count >= m_primTerseUpdatesPerPacket) | ||
3550 | ProcessPrimTerseUpdates(this, null); | ||
3551 | } | ||
3552 | } | 3551 | } |
3553 | 3552 | ||
3554 | void ProcessPrimTerseUpdates(object sender, ElapsedEventArgs e) | 3553 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) |
3555 | { | 3554 | { |
3556 | lock (m_primTerseUpdates) | 3555 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
3557 | { | 3556 | { |
3558 | if (m_primTerseUpdates.Count == 0) | 3557 | lock (m_avatarTerseUpdates.SyncRoot) |
3559 | { | 3558 | { |
3560 | lock (m_primTerseUpdateTimer) | 3559 | if (m_avatarTerseUpdates.Count > 0) |
3561 | m_primTerseUpdateTimer.Stop(); | 3560 | ProcessAvatarTerseUpdates(); |
3562 | |||
3563 | return; | ||
3564 | } | 3561 | } |
3562 | } | ||
3565 | 3563 | ||
3566 | ImprovedTerseObjectUpdatePacket outPacket = | 3564 | if ((categories & ThrottleOutPacketTypeFlags.State) != 0) |
3567 | (ImprovedTerseObjectUpdatePacket) | 3565 | { |
3568 | PacketPool.Instance.GetPacket( | 3566 | lock (m_primFullUpdates.SyncRoot) |
3569 | PacketType.ImprovedTerseObjectUpdate); | ||
3570 | |||
3571 | outPacket.RegionData.RegionHandle = | ||
3572 | Scene.RegionInfo.RegionHandle; | ||
3573 | outPacket.RegionData.TimeDilation = | ||
3574 | (ushort)(Scene.TimeDilation * ushort.MaxValue); | ||
3575 | |||
3576 | int max = m_primTerseUpdates.Count; | ||
3577 | if (max > m_primTerseUpdatesPerPacket) | ||
3578 | max = m_primTerseUpdatesPerPacket; | ||
3579 | |||
3580 | int count = 0; | ||
3581 | int size = 0; | ||
3582 | |||
3583 | byte[] zerobuffer = new byte[1024]; | ||
3584 | byte[] blockbuffer = new byte[1024]; | ||
3585 | |||
3586 | for (count = 0 ; count < max ; count++) | ||
3587 | { | 3567 | { |
3588 | int length = 0; | 3568 | if (m_primFullUpdates.Count > 0) |
3589 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); | 3569 | ProcessPrimFullUpdates(); |
3590 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | ||
3591 | if (size + length > Packet.MTU) | ||
3592 | break; | ||
3593 | size += length; | ||
3594 | } | 3570 | } |
3595 | 3571 | ||
3596 | outPacket.ObjectData = | 3572 | lock (m_primTerseUpdates.SyncRoot) |
3597 | new ImprovedTerseObjectUpdatePacket. | ||
3598 | ObjectDataBlock[count]; | ||
3599 | |||
3600 | for (int index = 0 ; index < count ; index++) | ||
3601 | { | 3573 | { |
3602 | outPacket.ObjectData[index] = m_primTerseUpdates[0]; | 3574 | if (m_primTerseUpdates.Count > 0) |
3603 | m_primTerseUpdates.RemoveAt(0); | 3575 | ProcessPrimTerseUpdates(); |
3604 | } | 3576 | } |
3577 | } | ||
3605 | 3578 | ||
3606 | outPacket.Header.Reliable = false; | 3579 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) |
3607 | outPacket.Header.Zerocoded = true; | 3580 | { |
3608 | OutPacket(outPacket, ThrottleOutPacketType.State); | 3581 | ProcessTextureRequests(); |
3609 | |||
3610 | if (m_primTerseUpdates.Count == 0) | ||
3611 | lock (m_primTerseUpdateTimer) | ||
3612 | m_primTerseUpdateTimer.Stop(); | ||
3613 | } | 3582 | } |
3614 | } | 3583 | } |
3615 | 3584 | ||
3616 | public void FlushPrimUpdates() | 3585 | void ProcessTextureRequests() |
3617 | { | 3586 | { |
3618 | while (m_primFullUpdates.Count > 0) | 3587 | if (m_imageManager != null) |
3619 | { | 3588 | m_imageManager.ProcessImageQueue(m_textureSendLimit); |
3620 | ProcessPrimFullUpdates(this, null); | ||
3621 | } | ||
3622 | while (m_primTerseUpdates.Count > 0) | ||
3623 | { | ||
3624 | ProcessPrimTerseUpdates(this, null); | ||
3625 | } | ||
3626 | while (m_avatarTerseUpdates.Count > 0) | ||
3627 | { | ||
3628 | ProcessAvatarTerseUpdates(this, null); | ||
3629 | } | ||
3630 | } | 3589 | } |
3631 | 3590 | ||
3632 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 3591 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
@@ -3659,7 +3618,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3659 | newPack.Header.Zerocoded = true; | 3618 | newPack.Header.Zerocoded = true; |
3660 | OutPacket(newPack, ThrottleOutPacketType.Asset); | 3619 | OutPacket(newPack, ThrottleOutPacketType.Asset); |
3661 | } | 3620 | } |
3662 | 3621 | ||
3663 | public void SendInitiateDownload(string simFileName, string clientFileName) | 3622 | public void SendInitiateDownload(string simFileName, string clientFileName) |
3664 | { | 3623 | { |
3665 | InitiateDownloadPacket newPack = new InitiateDownloadPacket(); | 3624 | InitiateDownloadPacket newPack = new InitiateDownloadPacket(); |
@@ -3668,7 +3627,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3668 | newPack.FileData.ViewerFilename = Utils.StringToBytes(clientFileName); | 3627 | newPack.FileData.ViewerFilename = Utils.StringToBytes(clientFileName); |
3669 | OutPacket(newPack, ThrottleOutPacketType.Asset); | 3628 | OutPacket(newPack, ThrottleOutPacketType.Asset); |
3670 | } | 3629 | } |
3671 | 3630 | ||
3672 | public void SendImageFirstPart( | 3631 | public void SendImageFirstPart( |
3673 | ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) | 3632 | ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) |
3674 | { | 3633 | { |
@@ -3810,8 +3769,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3810 | OutPacket(proper, ThrottleOutPacketType.Task); | 3769 | OutPacket(proper, ThrottleOutPacketType.Task); |
3811 | } | 3770 | } |
3812 | 3771 | ||
3813 | #endregion | ||
3814 | |||
3815 | #region Estate Data Sending Methods | 3772 | #region Estate Data Sending Methods |
3816 | 3773 | ||
3817 | private static bool convertParamStringToBool(byte[] field) | 3774 | private static bool convertParamStringToBool(byte[] field) |
@@ -3858,7 +3815,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3858 | 3815 | ||
3859 | public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID) | 3816 | public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID) |
3860 | { | 3817 | { |
3861 | List<UUID>BannedUsers = new List<UUID>(); | 3818 | List<UUID> BannedUsers = new List<UUID>(); |
3862 | 3819 | ||
3863 | for (int i = 0; i < bl.Length; i++) | 3820 | for (int i = 0; i < bl.Length; i++) |
3864 | { | 3821 | { |
@@ -3922,7 +3879,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3922 | rinfoblk.UseEstateSun = args.useEstateSun; | 3879 | rinfoblk.UseEstateSun = args.useEstateSun; |
3923 | rinfoblk.WaterHeight = args.waterHeight; | 3880 | rinfoblk.WaterHeight = args.waterHeight; |
3924 | rinfoblk.SimName = Utils.StringToBytes(args.simName); | 3881 | rinfoblk.SimName = Utils.StringToBytes(args.simName); |
3925 | 3882 | ||
3926 | rinfopack.RegionInfo2 = new RegionInfoPacket.RegionInfo2Block(); | 3883 | rinfopack.RegionInfo2 = new RegionInfoPacket.RegionInfo2Block(); |
3927 | rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue; | 3884 | rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue; |
3928 | rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue; | 3885 | rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue; |
@@ -4169,7 +4126,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4169 | 4126 | ||
4170 | public void SendLandObjectOwners(LandData land, List<UUID> groups, Dictionary<UUID, int> ownersAndCount) | 4127 | public void SendLandObjectOwners(LandData land, List<UUID> groups, Dictionary<UUID, int> ownersAndCount) |
4171 | { | 4128 | { |
4172 | 4129 | ||
4173 | 4130 | ||
4174 | int notifyCount = ownersAndCount.Count; | 4131 | int notifyCount = ownersAndCount.Count; |
4175 | ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply); | 4132 | ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply); |
@@ -4218,325 +4175,223 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4218 | 4175 | ||
4219 | #region Helper Methods | 4176 | #region Helper Methods |
4220 | 4177 | ||
4221 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateAvatarImprovedBlock(uint localID, Vector3 pos, | 4178 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendAvatarTerseData data) |
4222 | Vector3 velocity, | ||
4223 | Quaternion rotation) | ||
4224 | { | 4179 | { |
4225 | byte[] bytes = new byte[60]; | 4180 | return CreateImprovedTerseBlock(true, data.LocalID, 0, data.CollisionPlane, data.Position, data.Velocity, |
4226 | int i = 0; | 4181 | data.Acceleration, data.Rotation, Vector3.Zero, data.TextureEntry); |
4227 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = PacketPool.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | ||
4228 | |||
4229 | dat.TextureEntry = new byte[0]; // AvatarTemplate.TextureEntry; | ||
4230 | |||
4231 | uint ID = localID; | ||
4232 | |||
4233 | bytes[i++] = (byte)(ID % 256); | ||
4234 | bytes[i++] = (byte)((ID >> 8) % 256); | ||
4235 | bytes[i++] = (byte)((ID >> 16) % 256); | ||
4236 | bytes[i++] = (byte)((ID >> 24) % 256); | ||
4237 | bytes[i++] = 0; | ||
4238 | bytes[i++] = 1; | ||
4239 | i += 14; | ||
4240 | bytes[i++] = 128; | ||
4241 | bytes[i++] = 63; | ||
4242 | |||
4243 | byte[] pb = pos.GetBytes(); | ||
4244 | Array.Copy(pb, 0, bytes, i, pb.Length); | ||
4245 | i += 12; | ||
4246 | |||
4247 | Vector3 internDirec = new Vector3(velocity.X, velocity.Y, velocity.Z); | ||
4248 | |||
4249 | internDirec = internDirec / 128.0f; | ||
4250 | internDirec.X += 1; | ||
4251 | internDirec.Y += 1; | ||
4252 | internDirec.Z += 1; | ||
4253 | |||
4254 | ushort InternVelocityX = (ushort)(32768 * internDirec.X); | ||
4255 | ushort InternVelocityY = (ushort)(32768 * internDirec.Y); | ||
4256 | ushort InternVelocityZ = (ushort)(32768 * internDirec.Z); | ||
4257 | |||
4258 | ushort ac = 32767; | ||
4259 | bytes[i++] = (byte)(InternVelocityX % 256); | ||
4260 | bytes[i++] = (byte)((InternVelocityX >> 8) % 256); | ||
4261 | bytes[i++] = (byte)(InternVelocityY % 256); | ||
4262 | bytes[i++] = (byte)((InternVelocityY >> 8) % 256); | ||
4263 | bytes[i++] = (byte)(InternVelocityZ % 256); | ||
4264 | bytes[i++] = (byte)((InternVelocityZ >> 8) % 256); | ||
4265 | |||
4266 | //accel | ||
4267 | bytes[i++] = (byte)(ac % 256); | ||
4268 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4269 | bytes[i++] = (byte)(ac % 256); | ||
4270 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4271 | bytes[i++] = (byte)(ac % 256); | ||
4272 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4273 | |||
4274 | //rotation | ||
4275 | ushort rw, rx, ry, rz; | ||
4276 | rw = (ushort)(32768 * (rotation.W + 1)); | ||
4277 | rx = (ushort)(32768 * (rotation.X + 1)); | ||
4278 | ry = (ushort)(32768 * (rotation.Y + 1)); | ||
4279 | rz = (ushort)(32768 * (rotation.Z + 1)); | ||
4280 | |||
4281 | //rot | ||
4282 | bytes[i++] = (byte)(rx % 256); | ||
4283 | bytes[i++] = (byte)((rx >> 8) % 256); | ||
4284 | bytes[i++] = (byte)(ry % 256); | ||
4285 | bytes[i++] = (byte)((ry >> 8) % 256); | ||
4286 | bytes[i++] = (byte)(rz % 256); | ||
4287 | bytes[i++] = (byte)((rz >> 8) % 256); | ||
4288 | bytes[i++] = (byte)(rw % 256); | ||
4289 | bytes[i++] = (byte)((rw >> 8) % 256); | ||
4290 | |||
4291 | //rotation vel | ||
4292 | bytes[i++] = (byte)(ac % 256); | ||
4293 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4294 | bytes[i++] = (byte)(ac % 256); | ||
4295 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4296 | bytes[i++] = (byte)(ac % 256); | ||
4297 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4298 | |||
4299 | dat.Data = bytes; | ||
4300 | |||
4301 | return (dat); | ||
4302 | } | 4182 | } |
4303 | 4183 | ||
4304 | /// <summary> | 4184 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendPrimitiveTerseData data) |
4305 | /// | ||
4306 | /// </summary> | ||
4307 | /// <param name="localID"></param> | ||
4308 | /// <param name="position"></param> | ||
4309 | /// <param name="rotation"></param> | ||
4310 | /// <returns></returns> | ||
4311 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreatePrimImprovedBlock(uint localID, | ||
4312 | Vector3 position, | ||
4313 | Quaternion rotation, | ||
4314 | Vector3 velocity, | ||
4315 | Vector3 rotationalvelocity, | ||
4316 | byte state) | ||
4317 | { | 4185 | { |
4318 | uint ID = localID; | 4186 | return CreateImprovedTerseBlock(false, data.LocalID, data.State, Vector4.Zero, data.Position, data.Velocity, |
4319 | byte[] bytes = new byte[60]; | 4187 | data.Acceleration, data.Rotation, data.AngularVelocity, data.TextureEntry); |
4320 | |||
4321 | int i = 0; | ||
4322 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = PacketPool.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | ||
4323 | dat.TextureEntry = new byte[0]; | ||
4324 | bytes[i++] = (byte)(ID % 256); | ||
4325 | bytes[i++] = (byte)((ID >> 8) % 256); | ||
4326 | bytes[i++] = (byte)((ID >> 16) % 256); | ||
4327 | bytes[i++] = (byte)((ID >> 24) % 256); | ||
4328 | bytes[i++] = (byte)(((state & 0xf0) >> 4) | ((state & 0x0f) << 4)); | ||
4329 | bytes[i++] = 0; | ||
4330 | |||
4331 | byte[] pb = position.GetBytes(); | ||
4332 | Array.Copy(pb, 0, bytes, i, pb.Length); | ||
4333 | i += 12; | ||
4334 | ushort ac = 32767; | ||
4335 | |||
4336 | ushort velx, vely, velz; | ||
4337 | Vector3 vel = new Vector3(velocity.X, velocity.Y, velocity.Z); | ||
4338 | |||
4339 | vel = vel / 128.0f; | ||
4340 | vel.X += 1; | ||
4341 | vel.Y += 1; | ||
4342 | vel.Z += 1; | ||
4343 | //vel | ||
4344 | velx = (ushort)(32768 * (vel.X)); | ||
4345 | vely = (ushort)(32768 * (vel.Y)); | ||
4346 | velz = (ushort)(32768 * (vel.Z)); | ||
4347 | |||
4348 | bytes[i++] = (byte)(velx % 256); | ||
4349 | bytes[i++] = (byte)((velx >> 8) % 256); | ||
4350 | bytes[i++] = (byte)(vely % 256); | ||
4351 | bytes[i++] = (byte)((vely >> 8) % 256); | ||
4352 | bytes[i++] = (byte)(velz % 256); | ||
4353 | bytes[i++] = (byte)((velz >> 8) % 256); | ||
4354 | |||
4355 | //accel | ||
4356 | bytes[i++] = (byte)(ac % 256); | ||
4357 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4358 | bytes[i++] = (byte)(ac % 256); | ||
4359 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4360 | bytes[i++] = (byte)(ac % 256); | ||
4361 | bytes[i++] = (byte)((ac >> 8) % 256); | ||
4362 | |||
4363 | ushort rw, rx, ry, rz; | ||
4364 | rw = (ushort)(32768 * (rotation.W + 1)); | ||
4365 | rx = (ushort)(32768 * (rotation.X + 1)); | ||
4366 | ry = (ushort)(32768 * (rotation.Y + 1)); | ||
4367 | rz = (ushort)(32768 * (rotation.Z + 1)); | ||
4368 | |||
4369 | //rot | ||
4370 | bytes[i++] = (byte)(rx % 256); | ||
4371 | bytes[i++] = (byte)((rx >> 8) % 256); | ||
4372 | bytes[i++] = (byte)(ry % 256); | ||
4373 | bytes[i++] = (byte)((ry >> 8) % 256); | ||
4374 | bytes[i++] = (byte)(rz % 256); | ||
4375 | bytes[i++] = (byte)((rz >> 8) % 256); | ||
4376 | bytes[i++] = (byte)(rw % 256); | ||
4377 | bytes[i++] = (byte)((rw >> 8) % 256); | ||
4378 | |||
4379 | //rotation vel | ||
4380 | Vector3 rvel = new Vector3(rotationalvelocity.X, rotationalvelocity.Y, rotationalvelocity.Z); | ||
4381 | |||
4382 | rvel = rvel / 128.0f; | ||
4383 | rvel.X += 1; | ||
4384 | rvel.Y += 1; | ||
4385 | rvel.Z += 1; | ||
4386 | //vel | ||
4387 | ushort rvelx = (ushort)(32768 * (rvel.X)); | ||
4388 | ushort rvely = (ushort)(32768 * (rvel.Y)); | ||
4389 | ushort rvelz = (ushort)(32768 * (rvel.Z)); | ||
4390 | |||
4391 | bytes[i++] = (byte)(rvelx % 256); | ||
4392 | bytes[i++] = (byte)((rvelx >> 8) % 256); | ||
4393 | bytes[i++] = (byte)(rvely % 256); | ||
4394 | bytes[i++] = (byte)((rvely >> 8) % 256); | ||
4395 | bytes[i++] = (byte)(rvelz % 256); | ||
4396 | bytes[i++] = (byte)((rvelz >> 8) % 256); | ||
4397 | dat.Data = bytes; | ||
4398 | |||
4399 | return dat; | ||
4400 | } | 4188 | } |
4401 | 4189 | ||
4402 | /// <summary> | 4190 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(bool avatar, uint localID, byte state, |
4403 | /// Create the ObjectDataBlock for a ObjectUpdatePacket (for a Primitive) | 4191 | Vector4 collisionPlane, Vector3 position, Vector3 velocity, Vector3 acceleration, Quaternion rotation, |
4404 | /// </summary> | 4192 | Vector3 angularVelocity, byte[] textureEntry) |
4405 | /// <param name="primData"></param> | 4193 | { |
4406 | /// <returns></returns> | 4194 | int pos = 0; |
4407 | protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(PrimitiveBaseShape primShape, uint flags) | 4195 | byte[] data = new byte[(avatar ? 60 : 44)]; |
4408 | { | ||
4409 | ObjectUpdatePacket.ObjectDataBlock objupdate = PacketPool.GetDataBlock<ObjectUpdatePacket.ObjectDataBlock>(); | ||
4410 | SetDefaultPrimPacketValues(objupdate); | ||
4411 | objupdate.UpdateFlags = flags; | ||
4412 | SetPrimPacketShapeData(objupdate, primShape); | ||
4413 | |||
4414 | if ((primShape.PCode == (byte)PCode.NewTree) || (primShape.PCode == (byte)PCode.Tree) || (primShape.PCode == (byte)PCode.Grass)) | ||
4415 | { | ||
4416 | objupdate.Data = new byte[1]; | ||
4417 | objupdate.Data[0] = primShape.State; | ||
4418 | } | ||
4419 | return objupdate; | ||
4420 | } | ||
4421 | |||
4422 | protected void SetPrimPacketShapeData(ObjectUpdatePacket.ObjectDataBlock objectData, PrimitiveBaseShape primData) | ||
4423 | { | ||
4424 | objectData.TextureEntry = primData.TextureEntry; | ||
4425 | objectData.PCode = primData.PCode; | ||
4426 | objectData.State = primData.State; | ||
4427 | objectData.PathBegin = primData.PathBegin; | ||
4428 | objectData.PathEnd = primData.PathEnd; | ||
4429 | objectData.PathScaleX = primData.PathScaleX; | ||
4430 | objectData.PathScaleY = primData.PathScaleY; | ||
4431 | objectData.PathShearX = primData.PathShearX; | ||
4432 | objectData.PathShearY = primData.PathShearY; | ||
4433 | objectData.PathSkew = primData.PathSkew; | ||
4434 | objectData.ProfileBegin = primData.ProfileBegin; | ||
4435 | objectData.ProfileEnd = primData.ProfileEnd; | ||
4436 | objectData.Scale = primData.Scale; | ||
4437 | objectData.PathCurve = primData.PathCurve; | ||
4438 | objectData.ProfileCurve = primData.ProfileCurve; | ||
4439 | objectData.ProfileHollow = primData.ProfileHollow; | ||
4440 | objectData.PathRadiusOffset = primData.PathRadiusOffset; | ||
4441 | objectData.PathRevolutions = primData.PathRevolutions; | ||
4442 | objectData.PathTaperX = primData.PathTaperX; | ||
4443 | objectData.PathTaperY = primData.PathTaperY; | ||
4444 | objectData.PathTwist = primData.PathTwist; | ||
4445 | objectData.PathTwistBegin = primData.PathTwistBegin; | ||
4446 | objectData.ExtraParams = primData.ExtraParams; | ||
4447 | } | ||
4448 | 4196 | ||
4449 | /// <summary> | 4197 | // LocalID |
4450 | /// Set some default values in a ObjectUpdatePacket | 4198 | Utils.UIntToBytes(localID, data, pos); |
4451 | /// </summary> | 4199 | pos += 4; |
4452 | /// <param name="objdata"></param> | ||
4453 | protected void SetDefaultPrimPacketValues(ObjectUpdatePacket.ObjectDataBlock objdata) | ||
4454 | { | ||
4455 | objdata.PSBlock = new byte[0]; | ||
4456 | objdata.ExtraParams = new byte[1]; | ||
4457 | objdata.MediaURL = new byte[0]; | ||
4458 | objdata.NameValue = new byte[0]; | ||
4459 | objdata.Text = new byte[0]; | ||
4460 | objdata.TextColor = new byte[4]; | ||
4461 | objdata.JointAxisOrAnchor = new Vector3(0, 0, 0); | ||
4462 | objdata.JointPivot = new Vector3(0, 0, 0); | ||
4463 | objdata.Material = 3; | ||
4464 | objdata.TextureAnim = new byte[0]; | ||
4465 | objdata.Sound = UUID.Zero; | ||
4466 | objdata.State = 0; | ||
4467 | objdata.Data = new byte[0]; | ||
4468 | |||
4469 | objdata.ObjectData = new byte[60]; | ||
4470 | objdata.ObjectData[46] = 128; | ||
4471 | objdata.ObjectData[47] = 63; | ||
4472 | } | ||
4473 | 4200 | ||
4474 | /// <summary> | 4201 | // Avatar/CollisionPlane |
4475 | /// | 4202 | data[pos++] = state; |
4476 | /// </summary> | 4203 | if (avatar) |
4477 | /// <returns></returns> | 4204 | { |
4478 | public ObjectUpdatePacket.ObjectDataBlock CreateDefaultAvatarPacket(byte[] textureEntry) | 4205 | data[pos++] = 1; |
4479 | { | 4206 | |
4480 | ObjectUpdatePacket.ObjectDataBlock objdata = PacketPool.GetDataBlock<ObjectUpdatePacket.ObjectDataBlock>(); | 4207 | if (collisionPlane == Vector4.Zero) |
4481 | // new OpenMetaverse.Packets.ObjectUpdatePacket.ObjectDataBlock(data1, ref i); | 4208 | collisionPlane = Vector4.UnitW; |
4482 | 4209 | ||
4483 | SetDefaultAvatarPacketValues(ref objdata); | 4210 | collisionPlane.ToBytes(data, pos); |
4484 | objdata.UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24); | 4211 | pos += 16; |
4485 | objdata.PathCurve = 16; | 4212 | } |
4486 | objdata.ProfileCurve = 1; | 4213 | else |
4487 | objdata.PathScaleX = 100; | ||
4488 | objdata.PathScaleY = 100; | ||
4489 | objdata.ParentID = 0; | ||
4490 | objdata.OwnerID = UUID.Zero; | ||
4491 | objdata.Scale = new Vector3(1, 1, 1); | ||
4492 | objdata.PCode = (byte)PCode.Avatar; | ||
4493 | if (textureEntry != null) | ||
4494 | { | 4214 | { |
4495 | objdata.TextureEntry = textureEntry; | 4215 | ++pos; |
4496 | } | 4216 | } |
4497 | Vector3 pos = new Vector3(objdata.ObjectData, 16); | ||
4498 | pos.X = 100f; | ||
4499 | objdata.ID = 8880000; | ||
4500 | objdata.NameValue = Utils.StringToBytes("FirstName STRING RW SV Test \nLastName STRING RW SV User "); | ||
4501 | //Vector3 pos2 = new Vector3(100f, 100f, 23f); | ||
4502 | //objdata.FullID=user.AgentId; | ||
4503 | byte[] pb = pos.GetBytes(); | ||
4504 | Array.Copy(pb, 0, objdata.ObjectData, 16, pb.Length); | ||
4505 | 4217 | ||
4506 | return objdata; | 4218 | // Position |
4507 | } | 4219 | position.ToBytes(data, pos); |
4220 | pos += 12; | ||
4508 | 4221 | ||
4509 | /// <summary> | 4222 | // Velocity |
4510 | /// | 4223 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2; |
4511 | /// </summary> | 4224 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2; |
4512 | /// <param name="objdata"></param> | 4225 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2; |
4513 | protected void SetDefaultAvatarPacketValues(ref ObjectUpdatePacket.ObjectDataBlock objdata) | 4226 | |
4514 | { | 4227 | // Acceleration |
4515 | objdata.PSBlock = new byte[0]; | 4228 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2; |
4516 | objdata.ExtraParams = new byte[1]; | 4229 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2; |
4517 | objdata.MediaURL = new byte[0]; | 4230 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2; |
4518 | objdata.NameValue = new byte[0]; | 4231 | |
4519 | objdata.Text = new byte[0]; | 4232 | // Rotation |
4520 | objdata.TextColor = new byte[4]; | 4233 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.X, -1.0f, 1.0f), data, pos); pos += 2; |
4521 | objdata.JointAxisOrAnchor = new Vector3(0, 0, 0); | 4234 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Y, -1.0f, 1.0f), data, pos); pos += 2; |
4522 | objdata.JointPivot = new Vector3(0, 0, 0); | 4235 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Z, -1.0f, 1.0f), data, pos); pos += 2; |
4523 | objdata.Material = 4; | 4236 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2; |
4524 | objdata.TextureAnim = new byte[0]; | 4237 | |
4525 | objdata.Sound = UUID.Zero; | 4238 | // Angular Velocity |
4526 | Primitive.TextureEntry ntex = new Primitive.TextureEntry(new UUID("00000000-0000-0000-5005-000000000005")); | 4239 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2; |
4527 | objdata.TextureEntry = ntex.GetBytes(); | 4240 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; |
4528 | 4241 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; | |
4529 | objdata.State = 0; | 4242 | |
4530 | objdata.Data = new byte[0]; | 4243 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); |
4531 | 4244 | block.Data = data; | |
4532 | objdata.ObjectData = new byte[76]; | 4245 | |
4533 | objdata.ObjectData[15] = 128; | 4246 | if (textureEntry != null && textureEntry.Length > 0) |
4534 | objdata.ObjectData[16] = 63; | 4247 | { |
4535 | objdata.ObjectData[56] = 128; | 4248 | byte[] teBytesFinal = new byte[textureEntry.Length + 4]; |
4536 | objdata.ObjectData[61] = 102; | 4249 | |
4537 | objdata.ObjectData[62] = 40; | 4250 | // Texture Length |
4538 | objdata.ObjectData[63] = 61; | 4251 | Utils.IntToBytes(textureEntry.Length, textureEntry, 0); |
4539 | objdata.ObjectData[64] = 189; | 4252 | // Texture |
4253 | Buffer.BlockCopy(textureEntry, 0, teBytesFinal, 4, textureEntry.Length); | ||
4254 | |||
4255 | block.TextureEntry = teBytesFinal; | ||
4256 | } | ||
4257 | else | ||
4258 | { | ||
4259 | block.TextureEntry = Utils.EmptyBytes; | ||
4260 | } | ||
4261 | |||
4262 | return block; | ||
4263 | } | ||
4264 | |||
4265 | protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(SendAvatarData data) | ||
4266 | { | ||
4267 | byte[] objectData = new byte[76]; | ||
4268 | |||
4269 | Vector4.UnitW.ToBytes(objectData, 0); // TODO: Collision plane support | ||
4270 | data.Position.ToBytes(objectData, 16); | ||
4271 | //data.Velocity.ToBytes(objectData, 28); | ||
4272 | //data.Acceleration.ToBytes(objectData, 40); | ||
4273 | data.Rotation.ToBytes(objectData, 52); | ||
4274 | //data.AngularVelocity.ToBytes(objectData, 64); | ||
4275 | |||
4276 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | ||
4277 | |||
4278 | update.Data = Utils.EmptyBytes; | ||
4279 | update.ExtraParams = new byte[1]; | ||
4280 | update.FullID = data.AvatarID; | ||
4281 | update.ID = data.AvatarLocalID; | ||
4282 | update.Material = (byte)Material.Flesh; | ||
4283 | update.MediaURL = Utils.EmptyBytes; | ||
4284 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.FirstName + "\nLastName STRING RW SV " + | ||
4285 | data.LastName + "\nTitle STRING RW SV " + data.GroupTitle); | ||
4286 | update.ObjectData = objectData; | ||
4287 | update.ParentID = data.ParentID; | ||
4288 | update.PathCurve = 16; | ||
4289 | update.PathScaleX = 100; | ||
4290 | update.PathScaleY = 100; | ||
4291 | update.PCode = (byte)PCode.Avatar; | ||
4292 | update.ProfileCurve = 1; | ||
4293 | update.PSBlock = Utils.EmptyBytes; | ||
4294 | update.Scale = Vector3.One; | ||
4295 | update.Text = Utils.EmptyBytes; | ||
4296 | update.TextColor = new byte[4]; | ||
4297 | update.TextureAnim = Utils.EmptyBytes; | ||
4298 | update.TextureEntry = data.TextureEntry ?? Utils.EmptyBytes; | ||
4299 | update.UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24); // TODO: Replace these numbers with PrimFlags | ||
4300 | |||
4301 | return update; | ||
4302 | } | ||
4303 | |||
4304 | protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SendPrimitiveData data) | ||
4305 | { | ||
4306 | byte[] objectData = new byte[60]; | ||
4307 | data.pos.ToBytes(objectData, 0); | ||
4308 | data.vel.ToBytes(objectData, 12); | ||
4309 | data.acc.ToBytes(objectData, 24); | ||
4310 | data.rotation.ToBytes(objectData, 36); | ||
4311 | data.rvel.ToBytes(objectData, 48); | ||
4312 | |||
4313 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | ||
4314 | update.ClickAction = (byte)data.clickAction; | ||
4315 | update.CRC = 0; | ||
4316 | update.ExtraParams = data.primShape.ExtraParams ?? Utils.EmptyBytes; | ||
4317 | update.FullID = data.objectID; | ||
4318 | update.ID = data.localID; | ||
4319 | //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated | ||
4320 | //update.JointPivot = Vector3.Zero; | ||
4321 | //update.JointType = 0; | ||
4322 | update.Material = data.material; | ||
4323 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim | ||
4324 | if (data.attachment) | ||
4325 | { | ||
4326 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.AssetId); | ||
4327 | update.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16)); | ||
4328 | } | ||
4329 | else | ||
4330 | { | ||
4331 | update.NameValue = Utils.EmptyBytes; | ||
4332 | update.State = data.primShape.State; | ||
4333 | } | ||
4334 | update.ObjectData = objectData; | ||
4335 | update.ParentID = data.parentID; | ||
4336 | update.PathBegin = data.primShape.PathBegin; | ||
4337 | update.PathCurve = data.primShape.PathCurve; | ||
4338 | update.PathEnd = data.primShape.PathEnd; | ||
4339 | update.PathRadiusOffset = data.primShape.PathRadiusOffset; | ||
4340 | update.PathRevolutions = data.primShape.PathRevolutions; | ||
4341 | update.PathScaleX = data.primShape.PathScaleX; | ||
4342 | update.PathScaleY = data.primShape.PathScaleY; | ||
4343 | update.PathShearX = data.primShape.PathShearX; | ||
4344 | update.PathShearY = data.primShape.PathShearY; | ||
4345 | update.PathSkew = data.primShape.PathSkew; | ||
4346 | update.PathTaperX = data.primShape.PathTaperX; | ||
4347 | update.PathTaperY = data.primShape.PathTaperY; | ||
4348 | update.PathTwist = data.primShape.PathTwist; | ||
4349 | update.PathTwistBegin = data.primShape.PathTwistBegin; | ||
4350 | update.PCode = data.primShape.PCode; | ||
4351 | update.ProfileBegin = data.primShape.ProfileBegin; | ||
4352 | update.ProfileCurve = data.primShape.ProfileCurve; | ||
4353 | update.ProfileEnd = data.primShape.ProfileEnd; | ||
4354 | update.ProfileHollow = data.primShape.ProfileHollow; | ||
4355 | update.PSBlock = data.particleSystem ?? Utils.EmptyBytes; | ||
4356 | update.TextColor = data.color ?? Color4.Black.GetBytes(true); | ||
4357 | update.TextureAnim = data.textureanim ?? Utils.EmptyBytes; | ||
4358 | update.TextureEntry = data.primShape.TextureEntry ?? Utils.EmptyBytes; | ||
4359 | update.Scale = data.primShape.Scale; | ||
4360 | update.Text = Util.StringToBytes256(data.text); | ||
4361 | update.UpdateFlags = (uint)data.flags; | ||
4362 | |||
4363 | if (data.SoundId != UUID.Zero) | ||
4364 | { | ||
4365 | update.Sound = data.SoundId; | ||
4366 | update.OwnerID = data.ownerID; | ||
4367 | update.Gain = (float)data.SoundVolume; | ||
4368 | update.Radius = (float)data.SoundRadius; | ||
4369 | update.Flags = data.SoundFlags; | ||
4370 | } | ||
4371 | |||
4372 | switch ((PCode)data.primShape.PCode) | ||
4373 | { | ||
4374 | case PCode.Grass: | ||
4375 | case PCode.Tree: | ||
4376 | case PCode.NewTree: | ||
4377 | update.Data = new byte[] { data.primShape.State }; | ||
4378 | break; | ||
4379 | default: | ||
4380 | // TODO: Support ScratchPad | ||
4381 | //if (prim.ScratchPad != null) | ||
4382 | //{ | ||
4383 | // update.Data = new byte[prim.ScratchPad.Length]; | ||
4384 | // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length); | ||
4385 | //} | ||
4386 | //else | ||
4387 | //{ | ||
4388 | // update.Data = Utils.EmptyBytes; | ||
4389 | //} | ||
4390 | update.Data = Utils.EmptyBytes; | ||
4391 | break; | ||
4392 | } | ||
4393 | |||
4394 | return update; | ||
4540 | } | 4395 | } |
4541 | 4396 | ||
4542 | public void SendNameReply(UUID profileId, string firstname, string lastname) | 4397 | public void SendNameReply(UUID profileId, string firstname, string lastname) |
@@ -4546,8 +4401,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4546 | packet.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[1]; | 4401 | packet.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[1]; |
4547 | packet.UUIDNameBlock[0] = new UUIDNameReplyPacket.UUIDNameBlockBlock(); | 4402 | packet.UUIDNameBlock[0] = new UUIDNameReplyPacket.UUIDNameBlockBlock(); |
4548 | packet.UUIDNameBlock[0].ID = profileId; | 4403 | packet.UUIDNameBlock[0].ID = profileId; |
4549 | packet.UUIDNameBlock[0].FirstName = Utils.StringToBytes(firstname); | 4404 | packet.UUIDNameBlock[0].FirstName = Util.StringToBytes256(firstname); |
4550 | packet.UUIDNameBlock[0].LastName = Utils.StringToBytes(lastname); | 4405 | packet.UUIDNameBlock[0].LastName = Util.StringToBytes256(lastname); |
4551 | 4406 | ||
4552 | OutPacket(packet, ThrottleOutPacketType.Task); | 4407 | OutPacket(packet, ThrottleOutPacketType.Task); |
4553 | } | 4408 | } |
@@ -4593,7 +4448,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4593 | 4448 | ||
4594 | private bool HandleMoneyTransferRequest(IClientAPI sender, Packet Pack) | 4449 | private bool HandleMoneyTransferRequest(IClientAPI sender, Packet Pack) |
4595 | { | 4450 | { |
4596 | MoneyTransferRequestPacket money = (MoneyTransferRequestPacket) Pack; | 4451 | MoneyTransferRequestPacket money = (MoneyTransferRequestPacket)Pack; |
4597 | // validate the agent owns the agentID and sessionID | 4452 | // validate the agent owns the agentID and sessionID |
4598 | if (money.MoneyData.SourceID == sender.AgentId && money.AgentData.AgentID == sender.AgentId && | 4453 | if (money.MoneyData.SourceID == sender.AgentId && money.AgentData.AgentID == sender.AgentId && |
4599 | money.AgentData.SessionID == sender.SessionId) | 4454 | money.AgentData.SessionID == sender.SessionId) |
@@ -4614,7 +4469,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4614 | 4469 | ||
4615 | private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack) | 4470 | private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack) |
4616 | { | 4471 | { |
4617 | ParcelBuyPacket parcel = (ParcelBuyPacket) Pack; | 4472 | ParcelBuyPacket parcel = (ParcelBuyPacket)Pack; |
4618 | if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == SessionId) | 4473 | if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == SessionId) |
4619 | { | 4474 | { |
4620 | ParcelBuy handlerParcelBuy = OnParcelBuy; | 4475 | ParcelBuy handlerParcelBuy = OnParcelBuy; |
@@ -4634,7 +4489,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4634 | private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack) | 4489 | private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack) |
4635 | { | 4490 | { |
4636 | UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack; | 4491 | UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack; |
4637 | 4492 | ||
4638 | 4493 | ||
4639 | for (int i = 0; i < upack.UUIDNameBlock.Length; i++) | 4494 | for (int i = 0; i < upack.UUIDNameBlock.Length; i++) |
4640 | { | 4495 | { |
@@ -4650,7 +4505,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4650 | 4505 | ||
4651 | public bool HandleGenericMessage(IClientAPI sender, Packet pack) | 4506 | public bool HandleGenericMessage(IClientAPI sender, Packet pack) |
4652 | { | 4507 | { |
4653 | GenericMessagePacket gmpack = (GenericMessagePacket) pack; | 4508 | GenericMessagePacket gmpack = (GenericMessagePacket)pack; |
4654 | if (m_genericPacketHandlers.Count == 0) return false; | 4509 | if (m_genericPacketHandlers.Count == 0) return false; |
4655 | if (gmpack.AgentData.SessionID != SessionId) return false; | 4510 | if (gmpack.AgentData.SessionID != SessionId) return false; |
4656 | 4511 | ||
@@ -4743,8 +4598,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4743 | scriptQuestion.Data.TaskID = taskID; | 4598 | scriptQuestion.Data.TaskID = taskID; |
4744 | scriptQuestion.Data.ItemID = itemID; | 4599 | scriptQuestion.Data.ItemID = itemID; |
4745 | scriptQuestion.Data.Questions = question; | 4600 | scriptQuestion.Data.Questions = question; |
4746 | scriptQuestion.Data.ObjectName = Utils.StringToBytes(taskName); | 4601 | scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName); |
4747 | scriptQuestion.Data.ObjectOwner = Utils.StringToBytes(ownerName); | 4602 | scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName); |
4748 | 4603 | ||
4749 | OutPacket(scriptQuestion, ThrottleOutPacketType.Task); | 4604 | OutPacket(scriptQuestion, ThrottleOutPacketType.Task); |
4750 | } | 4605 | } |
@@ -4787,7 +4642,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4787 | { | 4642 | { |
4788 | if (((LogoutRequestPacket)packet).AgentData.SessionID != SessionId) return false; | 4643 | if (((LogoutRequestPacket)packet).AgentData.SessionID != SessionId) return false; |
4789 | } | 4644 | } |
4790 | 4645 | ||
4791 | return Logout(client); | 4646 | return Logout(client); |
4792 | } | 4647 | } |
4793 | 4648 | ||
@@ -4845,7 +4700,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4845 | 4700 | ||
4846 | cachedresp.Header.Zerocoded = true; | 4701 | cachedresp.Header.Zerocoded = true; |
4847 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | 4702 | OutPacket(cachedresp, ThrottleOutPacketType.Task); |
4848 | 4703 | ||
4849 | return true; | 4704 | return true; |
4850 | } | 4705 | } |
4851 | 4706 | ||
@@ -4895,7 +4750,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4895 | UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; | 4750 | UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; |
4896 | if (handlerUpdatePrimSingleRotation != null) | 4751 | if (handlerUpdatePrimSingleRotation != null) |
4897 | { | 4752 | { |
4898 | // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W); | 4753 | // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W); |
4899 | handlerUpdatePrimSingleRotation(localId, rot1, this); | 4754 | handlerUpdatePrimSingleRotation(localId, rot1, this); |
4900 | } | 4755 | } |
4901 | break; | 4756 | break; |
@@ -4906,8 +4761,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4906 | UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; | 4761 | UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; |
4907 | if (handlerUpdatePrimSingleRotationPosition != null) | 4762 | if (handlerUpdatePrimSingleRotationPosition != null) |
4908 | { | 4763 | { |
4909 | // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z); | 4764 | // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z); |
4910 | // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W); | 4765 | // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W); |
4911 | handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); | 4766 | handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); |
4912 | } | 4767 | } |
4913 | break; | 4768 | break; |
@@ -4918,7 +4773,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4918 | UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; | 4773 | UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; |
4919 | if (handlerUpdatePrimScale != null) | 4774 | if (handlerUpdatePrimScale != null) |
4920 | { | 4775 | { |
4921 | // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z); | 4776 | // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z); |
4922 | handlerUpdatePrimScale(localId, scale4, this); | 4777 | handlerUpdatePrimScale(localId, scale4, this); |
4923 | } | 4778 | } |
4924 | break; | 4779 | break; |
@@ -4957,7 +4812,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4957 | UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; | 4812 | UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; |
4958 | if (handlerUpdatePrimRotation != null) | 4813 | if (handlerUpdatePrimRotation != null) |
4959 | { | 4814 | { |
4960 | // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W); | 4815 | // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W); |
4961 | handlerUpdatePrimRotation(localId, rot3, this); | 4816 | handlerUpdatePrimRotation(localId, rot3, this); |
4962 | } | 4817 | } |
4963 | break; | 4818 | break; |
@@ -4968,8 +4823,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4968 | handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; | 4823 | handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; |
4969 | if (handlerUpdatePrimGroupRotation != null) | 4824 | if (handlerUpdatePrimGroupRotation != null) |
4970 | { | 4825 | { |
4971 | // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z); | 4826 | // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z); |
4972 | // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W); | 4827 | // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W); |
4973 | handlerUpdatePrimGroupRotation(localId, pos3, rot4, this); | 4828 | handlerUpdatePrimGroupRotation(localId, pos3, rot4, this); |
4974 | } | 4829 | } |
4975 | break; | 4830 | break; |
@@ -4980,7 +4835,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4980 | UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; | 4835 | UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; |
4981 | if (handlerUpdatePrimGroupScale != null) | 4836 | if (handlerUpdatePrimGroupScale != null) |
4982 | { | 4837 | { |
4983 | // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z); | 4838 | // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z); |
4984 | handlerUpdatePrimGroupScale(localId, scale7, this); | 4839 | handlerUpdatePrimGroupScale(localId, scale7, this); |
4985 | } | 4840 | } |
4986 | break; | 4841 | break; |
@@ -5138,7 +4993,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5138 | if (m_moneyBalance + debit >= 0) | 4993 | if (m_moneyBalance + debit >= 0) |
5139 | { | 4994 | { |
5140 | m_moneyBalance += debit; | 4995 | m_moneyBalance += debit; |
5141 | SendMoneyBalance(UUID.Zero, true, Utils.StringToBytes("Poof Poof!"), m_moneyBalance); | 4996 | SendMoneyBalance(UUID.Zero, true, Util.StringToBytes256("Poof Poof!"), m_moneyBalance); |
5142 | return true; | 4997 | return true; |
5143 | } | 4998 | } |
5144 | return false; | 4999 | return false; |
@@ -5212,7 +5067,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5212 | // Main packet processing conditional | 5067 | // Main packet processing conditional |
5213 | switch (Pack.Type) | 5068 | switch (Pack.Type) |
5214 | { | 5069 | { |
5215 | #region Scene/Avatar | 5070 | #region Scene/Avatar |
5216 | 5071 | ||
5217 | case PacketType.AvatarPropertiesRequest: | 5072 | case PacketType.AvatarPropertiesRequest: |
5218 | AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; | 5073 | AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; |
@@ -5463,7 +5318,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5463 | break; | 5318 | break; |
5464 | 5319 | ||
5465 | case PacketType.DeRezObject: | 5320 | case PacketType.DeRezObject: |
5466 | DeRezObjectPacket DeRezPacket = (DeRezObjectPacket) Pack; | 5321 | DeRezObjectPacket DeRezPacket = (DeRezObjectPacket)Pack; |
5467 | 5322 | ||
5468 | #region Packet Session and User Check | 5323 | #region Packet Session and User Check |
5469 | if (m_checkPackets) | 5324 | if (m_checkPackets) |
@@ -5484,13 +5339,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5484 | { | 5339 | { |
5485 | deRezIDs.Add(data.ObjectLocalID); | 5340 | deRezIDs.Add(data.ObjectLocalID); |
5486 | } | 5341 | } |
5487 | // It just so happens that the values on the DeRezAction enumerator match the Destination | 5342 | // It just so happens that the values on the DeRezAction enumerator match the Destination |
5488 | // values given by a Second Life client | 5343 | // values given by a Second Life client |
5489 | handlerDeRezObject(this, deRezIDs, | 5344 | handlerDeRezObject(this, deRezIDs, |
5490 | DeRezPacket.AgentBlock.GroupID, | 5345 | DeRezPacket.AgentBlock.GroupID, |
5491 | (DeRezAction)DeRezPacket.AgentBlock.Destination, | 5346 | (DeRezAction)DeRezPacket.AgentBlock.Destination, |
5492 | DeRezPacket.AgentBlock.DestinationID); | 5347 | DeRezPacket.AgentBlock.DestinationID); |
5493 | 5348 | ||
5494 | } | 5349 | } |
5495 | break; | 5350 | break; |
5496 | 5351 | ||
@@ -5594,7 +5449,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5594 | } | 5449 | } |
5595 | 5450 | ||
5596 | break; | 5451 | break; |
5597 | 5452 | ||
5598 | case PacketType.AgentIsNowWearing: | 5453 | case PacketType.AgentIsNowWearing: |
5599 | if (OnAvatarNowWearing != null) | 5454 | if (OnAvatarNowWearing != null) |
5600 | { | 5455 | { |
@@ -5798,7 +5653,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5798 | 5653 | ||
5799 | if (lastarg != null) | 5654 | if (lastarg != null) |
5800 | { | 5655 | { |
5801 | update = | 5656 | update = |
5802 | ( | 5657 | ( |
5803 | (x.BodyRotation != lastarg.BodyRotation) || | 5658 | (x.BodyRotation != lastarg.BodyRotation) || |
5804 | (x.CameraAtAxis != lastarg.CameraAtAxis) || | 5659 | (x.CameraAtAxis != lastarg.CameraAtAxis) || |
@@ -5991,7 +5846,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5991 | } | 5846 | } |
5992 | 5847 | ||
5993 | break; | 5848 | break; |
5994 | 5849 | ||
5995 | case PacketType.UserInfoRequest: | 5850 | case PacketType.UserInfoRequest: |
5996 | UserInfoRequest handlerUserInfoRequest = OnUserInfoRequest; | 5851 | UserInfoRequest handlerUserInfoRequest = OnUserInfoRequest; |
5997 | if (handlerUserInfoRequest != null) | 5852 | if (handlerUserInfoRequest != null) |
@@ -6003,7 +5858,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6003 | SendUserInfoReply(false, true, ""); | 5858 | SendUserInfoReply(false, true, ""); |
6004 | } | 5859 | } |
6005 | break; | 5860 | break; |
6006 | 5861 | ||
6007 | case PacketType.UpdateUserInfo: | 5862 | case PacketType.UpdateUserInfo: |
6008 | UpdateUserInfoPacket updateUserInfo = (UpdateUserInfoPacket)Pack; | 5863 | UpdateUserInfoPacket updateUserInfo = (UpdateUserInfoPacket)Pack; |
6009 | 5864 | ||
@@ -6030,7 +5885,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6030 | visible, this); | 5885 | visible, this); |
6031 | } | 5886 | } |
6032 | break; | 5887 | break; |
6033 | 5888 | ||
6034 | case PacketType.SetStartLocationRequest: | 5889 | case PacketType.SetStartLocationRequest: |
6035 | SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack; | 5890 | SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack; |
6036 | 5891 | ||
@@ -6088,9 +5943,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6088 | } | 5943 | } |
6089 | break; | 5944 | break; |
6090 | 5945 | ||
6091 | #endregion | 5946 | #endregion |
6092 | 5947 | ||
6093 | #region Objects/m_sceneObjects | 5948 | #region Objects/m_sceneObjects |
6094 | 5949 | ||
6095 | case PacketType.ObjectLink: | 5950 | case PacketType.ObjectLink: |
6096 | ObjectLinkPacket link = (ObjectLinkPacket)Pack; | 5951 | ObjectLinkPacket link = (ObjectLinkPacket)Pack; |
@@ -6121,7 +5976,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6121 | handlerLinkObjects(this, parentprimid, childrenprims); | 5976 | handlerLinkObjects(this, parentprimid, childrenprims); |
6122 | } | 5977 | } |
6123 | break; | 5978 | break; |
6124 | 5979 | ||
6125 | case PacketType.ObjectDelink: | 5980 | case PacketType.ObjectDelink: |
6126 | ObjectDelinkPacket delink = (ObjectDelinkPacket)Pack; | 5981 | ObjectDelinkPacket delink = (ObjectDelinkPacket)Pack; |
6127 | 5982 | ||
@@ -6150,7 +6005,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6150 | } | 6005 | } |
6151 | 6006 | ||
6152 | break; | 6007 | break; |
6153 | 6008 | ||
6154 | case PacketType.ObjectAdd: | 6009 | case PacketType.ObjectAdd: |
6155 | if (OnAddPrim != null) | 6010 | if (OnAddPrim != null) |
6156 | { | 6011 | { |
@@ -6180,7 +6035,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6180 | handlerAddPrim(AgentId, ActiveGroupId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); | 6035 | handlerAddPrim(AgentId, ActiveGroupId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); |
6181 | } | 6036 | } |
6182 | break; | 6037 | break; |
6183 | 6038 | ||
6184 | case PacketType.ObjectShape: | 6039 | case PacketType.ObjectShape: |
6185 | ObjectShapePacket shapePacket = (ObjectShapePacket)Pack; | 6040 | ObjectShapePacket shapePacket = (ObjectShapePacket)Pack; |
6186 | 6041 | ||
@@ -6225,7 +6080,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6225 | } | 6080 | } |
6226 | } | 6081 | } |
6227 | break; | 6082 | break; |
6228 | 6083 | ||
6229 | case PacketType.ObjectExtraParams: | 6084 | case PacketType.ObjectExtraParams: |
6230 | ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack; | 6085 | ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack; |
6231 | 6086 | ||
@@ -6241,7 +6096,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6241 | ObjectExtraParams handlerUpdateExtraParams = OnUpdateExtraParams; | 6096 | ObjectExtraParams handlerUpdateExtraParams = OnUpdateExtraParams; |
6242 | if (handlerUpdateExtraParams != null) | 6097 | if (handlerUpdateExtraParams != null) |
6243 | { | 6098 | { |
6244 | for (int i = 0 ; i < extraPar.ObjectData.Length ; i++) | 6099 | for (int i = 0; i < extraPar.ObjectData.Length; i++) |
6245 | { | 6100 | { |
6246 | handlerUpdateExtraParams(m_agentId, extraPar.ObjectData[i].ObjectLocalID, | 6101 | handlerUpdateExtraParams(m_agentId, extraPar.ObjectData[i].ObjectLocalID, |
6247 | extraPar.ObjectData[i].ParamType, | 6102 | extraPar.ObjectData[i].ParamType, |
@@ -6642,7 +6497,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6642 | break; | 6497 | break; |
6643 | case PacketType.ObjectName: | 6498 | case PacketType.ObjectName: |
6644 | ObjectNamePacket objName = (ObjectNamePacket)Pack; | 6499 | ObjectNamePacket objName = (ObjectNamePacket)Pack; |
6645 | 6500 | ||
6646 | #region Packet Session and User Check | 6501 | #region Packet Session and User Check |
6647 | if (m_checkPackets) | 6502 | if (m_checkPackets) |
6648 | { | 6503 | { |
@@ -6651,7 +6506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6651 | break; | 6506 | break; |
6652 | } | 6507 | } |
6653 | #endregion | 6508 | #endregion |
6654 | 6509 | ||
6655 | GenericCall7 handlerObjectName = null; | 6510 | GenericCall7 handlerObjectName = null; |
6656 | for (int i = 0; i < objName.ObjectData.Length; i++) | 6511 | for (int i = 0; i < objName.ObjectData.Length; i++) |
6657 | { | 6512 | { |
@@ -6884,14 +6739,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6884 | } | 6739 | } |
6885 | break; | 6740 | break; |
6886 | 6741 | ||
6887 | #endregion | 6742 | #endregion |
6888 | 6743 | ||
6889 | #region Inventory/Asset/Other related packets | 6744 | #region Inventory/Asset/Other related packets |
6890 | 6745 | ||
6891 | case PacketType.RequestImage: | 6746 | case PacketType.RequestImage: |
6892 | RequestImagePacket imageRequest = (RequestImagePacket)Pack; | 6747 | RequestImagePacket imageRequest = (RequestImagePacket)Pack; |
6893 | //m_log.Debug("image request: " + Pack.ToString()); | 6748 | //m_log.Debug("image request: " + Pack.ToString()); |
6894 | 6749 | ||
6895 | #region Packet Session and User Check | 6750 | #region Packet Session and User Check |
6896 | if (m_checkPackets) | 6751 | if (m_checkPackets) |
6897 | { | 6752 | { |
@@ -6915,7 +6770,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6915 | //handlerTextureRequest = OnRequestTexture; | 6770 | //handlerTextureRequest = OnRequestTexture; |
6916 | 6771 | ||
6917 | //if (handlerTextureRequest != null) | 6772 | //if (handlerTextureRequest != null) |
6918 | //OnRequestTexture(this, args); | 6773 | //OnRequestTexture(this, args); |
6919 | 6774 | ||
6920 | // in the end, we null this, so we have to check if it's null | 6775 | // in the end, we null this, so we have to check if it's null |
6921 | if (m_imageManager != null) | 6776 | if (m_imageManager != null) |
@@ -6961,7 +6816,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6961 | if (ti.OwnerID != AgentId) | 6816 | if (ti.OwnerID != AgentId) |
6962 | break; | 6817 | break; |
6963 | 6818 | ||
6964 | if ((ti.CurrentPermissions & ((uint)PermissionMask.Modify| (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) != ((uint)PermissionMask.Modify| (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 6819 | if ((ti.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) |
6965 | break; | 6820 | break; |
6966 | 6821 | ||
6967 | if (ti.AssetID != requestID) | 6822 | if (ti.AssetID != requestID) |
@@ -7019,7 +6874,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7019 | case PacketType.AssetUploadRequest: | 6874 | case PacketType.AssetUploadRequest: |
7020 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; | 6875 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; |
7021 | 6876 | ||
7022 | 6877 | ||
7023 | // m_log.Debug("upload request " + request.ToString()); | 6878 | // m_log.Debug("upload request " + request.ToString()); |
7024 | // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString()); | 6879 | // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString()); |
7025 | UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); | 6880 | UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); |
@@ -7036,7 +6891,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7036 | break; | 6891 | break; |
7037 | case PacketType.RequestXfer: | 6892 | case PacketType.RequestXfer: |
7038 | RequestXferPacket xferReq = (RequestXferPacket)Pack; | 6893 | RequestXferPacket xferReq = (RequestXferPacket)Pack; |
7039 | 6894 | ||
7040 | RequestXfer handlerRequestXfer = OnRequestXfer; | 6895 | RequestXfer handlerRequestXfer = OnRequestXfer; |
7041 | 6896 | ||
7042 | if (handlerRequestXfer != null) | 6897 | if (handlerRequestXfer != null) |
@@ -7055,7 +6910,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7055 | break; | 6910 | break; |
7056 | case PacketType.ConfirmXferPacket: | 6911 | case PacketType.ConfirmXferPacket: |
7057 | ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; | 6912 | ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; |
7058 | 6913 | ||
7059 | ConfirmXfer handlerConfirmXfer = OnConfirmXfer; | 6914 | ConfirmXfer handlerConfirmXfer = OnConfirmXfer; |
7060 | if (handlerConfirmXfer != null) | 6915 | if (handlerConfirmXfer != null) |
7061 | { | 6916 | { |
@@ -7150,7 +7005,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7150 | break; | 7005 | break; |
7151 | case PacketType.CreateInventoryItem: | 7006 | case PacketType.CreateInventoryItem: |
7152 | CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack; | 7007 | CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack; |
7153 | 7008 | ||
7154 | #region Packet Session and User Check | 7009 | #region Packet Session and User Check |
7155 | if (m_checkPackets) | 7010 | if (m_checkPackets) |
7156 | { | 7011 | { |
@@ -7243,7 +7098,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7243 | break; | 7098 | break; |
7244 | case PacketType.UpdateInventoryItem: | 7099 | case PacketType.UpdateInventoryItem: |
7245 | UpdateInventoryItemPacket inventoryItemUpdate = (UpdateInventoryItemPacket)Pack; | 7100 | UpdateInventoryItemPacket inventoryItemUpdate = (UpdateInventoryItemPacket)Pack; |
7246 | 7101 | ||
7247 | #region Packet Session and User Check | 7102 | #region Packet Session and User Check |
7248 | if (m_checkPackets) | 7103 | if (m_checkPackets) |
7249 | { | 7104 | { |
@@ -7735,7 +7590,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7735 | } | 7590 | } |
7736 | break; | 7591 | break; |
7737 | 7592 | ||
7738 | #endregion | 7593 | #endregion |
7739 | 7594 | ||
7740 | case PacketType.UUIDNameRequest: | 7595 | case PacketType.UUIDNameRequest: |
7741 | UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; | 7596 | UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; |
@@ -7750,7 +7605,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7750 | } | 7605 | } |
7751 | break; | 7606 | break; |
7752 | 7607 | ||
7753 | #region Parcel related packets | 7608 | #region Parcel related packets |
7754 | 7609 | ||
7755 | case PacketType.RegionHandleRequest: | 7610 | case PacketType.RegionHandleRequest: |
7756 | RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; | 7611 | RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; |
@@ -8131,9 +7986,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8131 | } | 7986 | } |
8132 | break; | 7987 | break; |
8133 | 7988 | ||
8134 | #endregion | 7989 | #endregion |
8135 | 7990 | ||
8136 | #region Estate Packets | 7991 | #region Estate Packets |
8137 | 7992 | ||
8138 | case PacketType.EstateOwnerMessage: | 7993 | case PacketType.EstateOwnerMessage: |
8139 | EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack; | 7994 | EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack; |
@@ -8167,21 +8022,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8167 | convertParamStringToBool(messagePacket.ParamList[7].Parameter), convertParamStringToBool(messagePacket.ParamList[8].Parameter)); | 8022 | convertParamStringToBool(messagePacket.ParamList[7].Parameter), convertParamStringToBool(messagePacket.ParamList[8].Parameter)); |
8168 | } | 8023 | } |
8169 | break; | 8024 | break; |
8170 | // case "texturebase": | 8025 | // case "texturebase": |
8171 | // if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | 8026 | // if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) |
8172 | // { | 8027 | // { |
8173 | // foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) | 8028 | // foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) |
8174 | // { | 8029 | // { |
8175 | // string s = Utils.BytesToString(block.Parameter); | 8030 | // string s = Utils.BytesToString(block.Parameter); |
8176 | // string[] splitField = s.Split(' '); | 8031 | // string[] splitField = s.Split(' '); |
8177 | // if (splitField.Length == 2) | 8032 | // if (splitField.Length == 2) |
8178 | // { | 8033 | // { |
8179 | // UUID tempUUID = new UUID(splitField[1]); | 8034 | // UUID tempUUID = new UUID(splitField[1]); |
8180 | // OnSetEstateTerrainBaseTexture(this, Convert.ToInt16(splitField[0]), tempUUID); | 8035 | // OnSetEstateTerrainBaseTexture(this, Convert.ToInt16(splitField[0]), tempUUID); |
8181 | // } | 8036 | // } |
8182 | // } | 8037 | // } |
8183 | // } | 8038 | // } |
8184 | // break; | 8039 | // break; |
8185 | case "texturedetail": | 8040 | case "texturedetail": |
8186 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | 8041 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) |
8187 | { | 8042 | { |
@@ -8423,7 +8278,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8423 | m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); | 8278 | m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); |
8424 | break; | 8279 | break; |
8425 | } | 8280 | } |
8426 | 8281 | ||
8427 | //int parcelID, uint reportType, uint requestflags, string filter | 8282 | //int parcelID, uint reportType, uint requestflags, string filter |
8428 | 8283 | ||
8429 | //lsrp.RequestData.ParcelLocalID; | 8284 | //lsrp.RequestData.ParcelLocalID; |
@@ -8463,9 +8318,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8463 | } | 8318 | } |
8464 | break; | 8319 | break; |
8465 | 8320 | ||
8466 | #endregion | 8321 | #endregion |
8467 | 8322 | ||
8468 | #region GodPackets | 8323 | #region GodPackets |
8469 | 8324 | ||
8470 | case PacketType.RequestGodlikePowers: | 8325 | case PacketType.RequestGodlikePowers: |
8471 | RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; | 8326 | RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; |
@@ -8511,9 +8366,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8511 | //OutPacket(kupack, ThrottleOutPacketType.Task); | 8366 | //OutPacket(kupack, ThrottleOutPacketType.Task); |
8512 | break; | 8367 | break; |
8513 | 8368 | ||
8514 | #endregion | 8369 | #endregion |
8515 | 8370 | ||
8516 | #region Economy/Transaction Packets | 8371 | #region Economy/Transaction Packets |
8517 | 8372 | ||
8518 | case PacketType.MoneyBalanceRequest: | 8373 | case PacketType.MoneyBalanceRequest: |
8519 | MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack; | 8374 | MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack; |
@@ -8537,7 +8392,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8537 | break; | 8392 | break; |
8538 | case PacketType.EconomyDataRequest: | 8393 | case PacketType.EconomyDataRequest: |
8539 | 8394 | ||
8540 | 8395 | ||
8541 | EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; | 8396 | EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; |
8542 | if (handlerEconomoyDataRequest != null) | 8397 | if (handlerEconomoyDataRequest != null) |
8543 | { | 8398 | { |
@@ -8613,9 +8468,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8613 | } | 8468 | } |
8614 | break; | 8469 | break; |
8615 | 8470 | ||
8616 | #endregion | 8471 | #endregion |
8617 | 8472 | ||
8618 | #region Script Packets | 8473 | #region Script Packets |
8619 | 8474 | ||
8620 | case PacketType.GetScriptRunning: | 8475 | case PacketType.GetScriptRunning: |
8621 | GetScriptRunningPacket scriptRunning = (GetScriptRunningPacket)Pack; | 8476 | GetScriptRunningPacket scriptRunning = (GetScriptRunningPacket)Pack; |
@@ -8665,9 +8520,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8665 | } | 8520 | } |
8666 | break; | 8521 | break; |
8667 | 8522 | ||
8668 | #endregion | 8523 | #endregion |
8669 | 8524 | ||
8670 | #region Gesture Managment | 8525 | #region Gesture Managment |
8671 | 8526 | ||
8672 | case PacketType.ActivateGestures: | 8527 | case PacketType.ActivateGestures: |
8673 | ActivateGesturesPacket activateGesturePacket = (ActivateGesturesPacket)Pack; | 8528 | ActivateGesturesPacket activateGesturePacket = (ActivateGesturesPacket)Pack; |
@@ -8734,21 +8589,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8734 | } | 8589 | } |
8735 | break; | 8590 | break; |
8736 | 8591 | ||
8737 | #endregion | 8592 | #endregion |
8738 | |||
8739 | 8593 | ||
8740 | #region unimplemented handlers | 8594 | case PacketType.AgentFOV: |
8595 | AgentFOVPacket fovPacket = (AgentFOVPacket)Pack; | ||
8741 | 8596 | ||
8742 | case PacketType.StartPingCheck: | 8597 | if (fovPacket.FOVBlock.GenCounter > m_agentFOVCounter) |
8743 | StartPingCheckPacket pingStart = (StartPingCheckPacket)Pack; | 8598 | { |
8744 | CompletePingCheckPacket pingComplete = new CompletePingCheckPacket(); | 8599 | m_agentFOVCounter = fovPacket.FOVBlock.GenCounter; |
8745 | pingComplete.PingID.PingID = pingStart.PingID.PingID; | 8600 | AgentFOV handlerAgentFOV = OnAgentFOV; |
8746 | m_udpServer.SendPacket(m_udpClient, pingComplete, ThrottleOutPacketType.Unknown, false); | 8601 | if (handlerAgentFOV != null) |
8602 | { | ||
8603 | handlerAgentFOV(this, fovPacket.FOVBlock.VerticalAngle); | ||
8604 | } | ||
8605 | } | ||
8747 | break; | 8606 | break; |
8748 | 8607 | ||
8749 | case PacketType.CompletePingCheck: | 8608 | #region unimplemented handlers |
8750 | // TODO: Do stats tracking or something with these? | ||
8751 | break; | ||
8752 | 8609 | ||
8753 | case PacketType.ViewerStats: | 8610 | case PacketType.ViewerStats: |
8754 | // TODO: handle this packet | 8611 | // TODO: handle this packet |
@@ -8771,8 +8628,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8771 | MapItemRequest handlerMapItemRequest = OnMapItemRequest; | 8628 | MapItemRequest handlerMapItemRequest = OnMapItemRequest; |
8772 | if (handlerMapItemRequest != null) | 8629 | if (handlerMapItemRequest != null) |
8773 | { | 8630 | { |
8774 | handlerMapItemRequest(this,mirpk.AgentData.Flags, mirpk.AgentData.EstateID, | 8631 | handlerMapItemRequest(this, mirpk.AgentData.Flags, mirpk.AgentData.EstateID, |
8775 | mirpk.AgentData.Godlike,mirpk.RequestData.ItemType, | 8632 | mirpk.AgentData.Godlike, mirpk.RequestData.ItemType, |
8776 | mirpk.RequestData.RegionHandle); | 8633 | mirpk.RequestData.RegionHandle); |
8777 | 8634 | ||
8778 | } | 8635 | } |
@@ -9080,7 +8937,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9080 | new GroupTitlesReplyPacket.GroupDataBlock(); | 8937 | new GroupTitlesReplyPacket.GroupDataBlock(); |
9081 | 8938 | ||
9082 | groupTitlesReply.GroupData[i].Title = | 8939 | groupTitlesReply.GroupData[i].Title = |
9083 | Utils.StringToBytes(d.Name); | 8940 | Util.StringToBytes256(d.Name); |
9084 | groupTitlesReply.GroupData[i].RoleID = | 8941 | groupTitlesReply.GroupData[i].RoleID = |
9085 | d.UUID; | 8942 | d.UUID; |
9086 | groupTitlesReply.GroupData[i].Selected = | 8943 | groupTitlesReply.GroupData[i].Selected = |
@@ -9117,10 +8974,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9117 | groupProfileRequest.GroupData.GroupID); | 8974 | groupProfileRequest.GroupData.GroupID); |
9118 | 8975 | ||
9119 | groupProfileReply.GroupData.GroupID = d.GroupID; | 8976 | groupProfileReply.GroupData.GroupID = d.GroupID; |
9120 | groupProfileReply.GroupData.Name = Utils.StringToBytes(d.Name); | 8977 | groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name); |
9121 | groupProfileReply.GroupData.Charter = Utils.StringToBytes(d.Charter); | 8978 | groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter); |
9122 | groupProfileReply.GroupData.ShowInList = d.ShowInList; | 8979 | groupProfileReply.GroupData.ShowInList = d.ShowInList; |
9123 | groupProfileReply.GroupData.MemberTitle = Utils.StringToBytes(d.MemberTitle); | 8980 | groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle); |
9124 | groupProfileReply.GroupData.PowersMask = d.PowersMask; | 8981 | groupProfileReply.GroupData.PowersMask = d.PowersMask; |
9125 | groupProfileReply.GroupData.InsigniaID = d.InsigniaID; | 8982 | groupProfileReply.GroupData.InsigniaID = d.InsigniaID; |
9126 | groupProfileReply.GroupData.FounderID = d.FounderID; | 8983 | groupProfileReply.GroupData.FounderID = d.FounderID; |
@@ -9180,7 +9037,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9180 | groupMembersRequestPacket.GroupData.RequestID; | 9037 | groupMembersRequestPacket.GroupData.RequestID; |
9181 | groupMembersReply.GroupData.MemberCount = memberCount; | 9038 | groupMembersReply.GroupData.MemberCount = memberCount; |
9182 | 9039 | ||
9183 | for (int i = 0 ; i < blockCount ; i++) | 9040 | for (int i = 0; i < blockCount; i++) |
9184 | { | 9041 | { |
9185 | GroupMembersData m = members[0]; | 9042 | GroupMembersData m = members[0]; |
9186 | members.RemoveAt(0); | 9043 | members.RemoveAt(0); |
@@ -9192,11 +9049,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9192 | groupMembersReply.MemberData[i].Contribution = | 9049 | groupMembersReply.MemberData[i].Contribution = |
9193 | m.Contribution; | 9050 | m.Contribution; |
9194 | groupMembersReply.MemberData[i].OnlineStatus = | 9051 | groupMembersReply.MemberData[i].OnlineStatus = |
9195 | Utils.StringToBytes(m.OnlineStatus); | 9052 | Util.StringToBytes256(m.OnlineStatus); |
9196 | groupMembersReply.MemberData[i].AgentPowers = | 9053 | groupMembersReply.MemberData[i].AgentPowers = |
9197 | m.AgentPowers; | 9054 | m.AgentPowers; |
9198 | groupMembersReply.MemberData[i].Title = | 9055 | groupMembersReply.MemberData[i].Title = |
9199 | Utils.StringToBytes(m.Title); | 9056 | Util.StringToBytes256(m.Title); |
9200 | groupMembersReply.MemberData[i].IsOwner = | 9057 | groupMembersReply.MemberData[i].IsOwner = |
9201 | m.IsOwner; | 9058 | m.IsOwner; |
9202 | } | 9059 | } |
@@ -9257,11 +9114,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9257 | groupRolesReply.RoleData[i].RoleID = | 9114 | groupRolesReply.RoleData[i].RoleID = |
9258 | d.RoleID; | 9115 | d.RoleID; |
9259 | groupRolesReply.RoleData[i].Name = | 9116 | groupRolesReply.RoleData[i].Name = |
9260 | Utils.StringToBytes(d.Name); | 9117 | Util.StringToBytes256(d.Name); |
9261 | groupRolesReply.RoleData[i].Title = | 9118 | groupRolesReply.RoleData[i].Title = |
9262 | Utils.StringToBytes(d.Title); | 9119 | Util.StringToBytes256(d.Title); |
9263 | groupRolesReply.RoleData[i].Description = | 9120 | groupRolesReply.RoleData[i].Description = |
9264 | Utils.StringToBytes(d.Description); | 9121 | Util.StringToBytes1024(d.Description); |
9265 | groupRolesReply.RoleData[i].Powers = | 9122 | groupRolesReply.RoleData[i].Powers = |
9266 | d.Powers; | 9123 | d.Powers; |
9267 | groupRolesReply.RoleData[i].Members = | 9124 | groupRolesReply.RoleData[i].Members = |
@@ -9317,7 +9174,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9317 | groupRoleMembersReply.MemberData = | 9174 | groupRoleMembersReply.MemberData = |
9318 | new GroupRoleMembersReplyPacket.MemberDataBlock[pairs]; | 9175 | new GroupRoleMembersReplyPacket.MemberDataBlock[pairs]; |
9319 | 9176 | ||
9320 | for (int i = 0 ; i < pairs ; i++) | 9177 | for (int i = 0; i < pairs; i++) |
9321 | { | 9178 | { |
9322 | GroupRoleMembersData d = mappings[0]; | 9179 | GroupRoleMembersData d = mappings[0]; |
9323 | mappings.RemoveAt(0); | 9180 | mappings.RemoveAt(0); |
@@ -9444,7 +9301,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9444 | ParcelDeedToGroup handlerParcelDeedToGroup = OnParcelDeedToGroup; | 9301 | ParcelDeedToGroup handlerParcelDeedToGroup = OnParcelDeedToGroup; |
9445 | if (handlerParcelDeedToGroup != null) | 9302 | if (handlerParcelDeedToGroup != null) |
9446 | { | 9303 | { |
9447 | handlerParcelDeedToGroup(parcelDeedToGroup.Data.LocalID, parcelDeedToGroup.Data.GroupID,this); | 9304 | handlerParcelDeedToGroup(parcelDeedToGroup.Data.LocalID, parcelDeedToGroup.Data.GroupID, this); |
9448 | 9305 | ||
9449 | } | 9306 | } |
9450 | } | 9307 | } |
@@ -9488,9 +9345,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9488 | groupNoticesListReply.Data[i].Timestamp = | 9345 | groupNoticesListReply.Data[i].Timestamp = |
9489 | g.Timestamp; | 9346 | g.Timestamp; |
9490 | groupNoticesListReply.Data[i].FromName = | 9347 | groupNoticesListReply.Data[i].FromName = |
9491 | Utils.StringToBytes(g.FromName); | 9348 | Util.StringToBytes256(g.FromName); |
9492 | groupNoticesListReply.Data[i].Subject = | 9349 | groupNoticesListReply.Data[i].Subject = |
9493 | Utils.StringToBytes(g.Subject); | 9350 | Util.StringToBytes256(g.Subject); |
9494 | groupNoticesListReply.Data[i].HasAttachment = | 9351 | groupNoticesListReply.Data[i].HasAttachment = |
9495 | g.HasAttachment; | 9352 | g.HasAttachment; |
9496 | groupNoticesListReply.Data[i].AssetType = | 9353 | groupNoticesListReply.Data[i].AssetType = |
@@ -9902,7 +9759,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9902 | 9759 | ||
9903 | PickDelete handlerPickDelete = OnPickDelete; | 9760 | PickDelete handlerPickDelete = OnPickDelete; |
9904 | if (handlerPickDelete != null) | 9761 | if (handlerPickDelete != null) |
9905 | handlerPickDelete(this, pickDelete.Data.PickID); | 9762 | handlerPickDelete(this, pickDelete.Data.PickID); |
9906 | break; | 9763 | break; |
9907 | case PacketType.PickGodDelete: | 9764 | case PacketType.PickGodDelete: |
9908 | PickGodDeletePacket pickGodDelete = | 9765 | PickGodDeletePacket pickGodDelete = |
@@ -9922,7 +9779,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9922 | handlerPickGodDelete(this, | 9779 | handlerPickGodDelete(this, |
9923 | pickGodDelete.AgentData.AgentID, | 9780 | pickGodDelete.AgentData.AgentID, |
9924 | pickGodDelete.Data.PickID, | 9781 | pickGodDelete.Data.PickID, |
9925 | pickGodDelete.Data.QueryID); | 9782 | pickGodDelete.Data.QueryID); |
9926 | break; | 9783 | break; |
9927 | case PacketType.PickInfoUpdate: | 9784 | case PacketType.PickInfoUpdate: |
9928 | PickInfoUpdatePacket pickInfoUpdate = | 9785 | PickInfoUpdatePacket pickInfoUpdate = |
@@ -10013,7 +9870,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10013 | m_log.Warn("[CLIENT]: unhandled packet " + Pack); | 9870 | m_log.Warn("[CLIENT]: unhandled packet " + Pack); |
10014 | break; | 9871 | break; |
10015 | 9872 | ||
10016 | #endregion | 9873 | #endregion |
10017 | } | 9874 | } |
10018 | 9875 | ||
10019 | PacketPool.Instance.ReturnPacket(Pack); | 9876 | PacketPool.Instance.ReturnPacket(Pack); |
@@ -10050,7 +9907,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10050 | //shape.Textures = ntex; | 9907 | //shape.Textures = ntex; |
10051 | return shape; | 9908 | return shape; |
10052 | } | 9909 | } |
10053 | 9910 | ||
10054 | public ClientInfo GetClientInfo() | 9911 | public ClientInfo GetClientInfo() |
10055 | { | 9912 | { |
10056 | ClientInfo info = m_udpClient.GetClientInfo(); | 9913 | ClientInfo info = m_udpClient.GetClientInfo(); |
@@ -10078,7 +9935,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10078 | { | 9935 | { |
10079 | ParcelMediaCommandMessagePacket commandMessagePacket = new ParcelMediaCommandMessagePacket(); | 9936 | ParcelMediaCommandMessagePacket commandMessagePacket = new ParcelMediaCommandMessagePacket(); |
10080 | commandMessagePacket.CommandBlock.Flags = flags; | 9937 | commandMessagePacket.CommandBlock.Flags = flags; |
10081 | commandMessagePacket.CommandBlock.Command =(uint) command; | 9938 | commandMessagePacket.CommandBlock.Command = (uint)command; |
10082 | commandMessagePacket.CommandBlock.Time = time; | 9939 | commandMessagePacket.CommandBlock.Time = time; |
10083 | 9940 | ||
10084 | OutPacket(commandMessagePacket, ThrottleOutPacketType.Unknown); | 9941 | OutPacket(commandMessagePacket, ThrottleOutPacketType.Unknown); |
@@ -10089,12 +9946,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10089 | byte mediaLoop) | 9946 | byte mediaLoop) |
10090 | { | 9947 | { |
10091 | ParcelMediaUpdatePacket updatePacket = new ParcelMediaUpdatePacket(); | 9948 | ParcelMediaUpdatePacket updatePacket = new ParcelMediaUpdatePacket(); |
10092 | updatePacket.DataBlock.MediaURL = Utils.StringToBytes(mediaUrl); | 9949 | updatePacket.DataBlock.MediaURL = Util.StringToBytes256(mediaUrl); |
10093 | updatePacket.DataBlock.MediaID = mediaTextureID; | 9950 | updatePacket.DataBlock.MediaID = mediaTextureID; |
10094 | updatePacket.DataBlock.MediaAutoScale = autoScale; | 9951 | updatePacket.DataBlock.MediaAutoScale = autoScale; |
10095 | 9952 | ||
10096 | updatePacket.DataBlockExtended.MediaType = Utils.StringToBytes(mediaType); | 9953 | updatePacket.DataBlockExtended.MediaType = Util.StringToBytes256(mediaType); |
10097 | updatePacket.DataBlockExtended.MediaDesc = Utils.StringToBytes(mediaDesc); | 9954 | updatePacket.DataBlockExtended.MediaDesc = Util.StringToBytes256(mediaDesc); |
10098 | updatePacket.DataBlockExtended.MediaWidth = mediaWidth; | 9955 | updatePacket.DataBlockExtended.MediaWidth = mediaWidth; |
10099 | updatePacket.DataBlockExtended.MediaHeight = mediaHeight; | 9956 | updatePacket.DataBlockExtended.MediaHeight = mediaHeight; |
10100 | updatePacket.DataBlockExtended.MediaLoop = mediaLoop; | 9957 | updatePacket.DataBlockExtended.MediaLoop = mediaLoop; |
@@ -10106,7 +9963,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10106 | 9963 | ||
10107 | #region Camera | 9964 | #region Camera |
10108 | 9965 | ||
10109 | public void SendSetFollowCamProperties (UUID objectID, SortedDictionary<int, float> parameters) | 9966 | public void SendSetFollowCamProperties(UUID objectID, SortedDictionary<int, float> parameters) |
10110 | { | 9967 | { |
10111 | SetFollowCamPropertiesPacket packet = (SetFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.SetFollowCamProperties); | 9968 | SetFollowCamPropertiesPacket packet = (SetFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.SetFollowCamProperties); |
10112 | packet.ObjectData.ObjectID = objectID; | 9969 | packet.ObjectData.ObjectID = objectID; |
@@ -10124,7 +9981,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10124 | OutPacket(packet, ThrottleOutPacketType.Task); | 9981 | OutPacket(packet, ThrottleOutPacketType.Task); |
10125 | } | 9982 | } |
10126 | 9983 | ||
10127 | public void SendClearFollowCamProperties (UUID objectID) | 9984 | public void SendClearFollowCamProperties(UUID objectID) |
10128 | { | 9985 | { |
10129 | ClearFollowCamPropertiesPacket packet = (ClearFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ClearFollowCamProperties); | 9986 | ClearFollowCamPropertiesPacket packet = (ClearFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ClearFollowCamProperties); |
10130 | packet.ObjectData.ObjectID = objectID; | 9987 | packet.ObjectData.ObjectID = objectID; |
@@ -10226,8 +10083,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10226 | { | 10083 | { |
10227 | return m_udpClient.GetStats(); | 10084 | return m_udpClient.GetStats(); |
10228 | } | 10085 | } |
10229 | 10086 | ||
10230 | public string XReport(string uptime, string version) | 10087 | public string XReport(string uptime, string version) |
10231 | { | 10088 | { |
10232 | return String.Empty; | 10089 | return String.Empty; |
10233 | } | 10090 | } |
@@ -10301,7 +10158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10301 | } | 10158 | } |
10302 | 10159 | ||
10303 | //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID); | 10160 | //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID); |
10304 | 10161 | ||
10305 | // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right. | 10162 | // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right. |
10306 | return; | 10163 | return; |
10307 | } | 10164 | } |
@@ -10371,5 +10228,167 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10371 | pack.TextureData.TextureID = textureID; | 10228 | pack.TextureData.TextureID = textureID; |
10372 | OutPacket(pack, ThrottleOutPacketType.Task); | 10229 | OutPacket(pack, ThrottleOutPacketType.Task); |
10373 | } | 10230 | } |
10231 | |||
10232 | #region PriorityQueue | ||
10233 | private class PriorityQueue<TPriority, TValue> | ||
10234 | { | ||
10235 | internal delegate bool UpdatePriorityHandler(ref TPriority priority, uint local_id); | ||
10236 | |||
10237 | private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[1]; | ||
10238 | private Dictionary<uint, LookupItem> m_lookupTable; | ||
10239 | private Comparison<TPriority> m_comparison; | ||
10240 | private object m_syncRoot = new object(); | ||
10241 | |||
10242 | internal PriorityQueue() : | ||
10243 | this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, Comparer<TPriority>.Default) { } | ||
10244 | internal PriorityQueue(int capacity) : | ||
10245 | this(capacity, Comparer<TPriority>.Default) { } | ||
10246 | internal PriorityQueue(IComparer<TPriority> comparer) : | ||
10247 | this(new Comparison<TPriority>(comparer.Compare)) { } | ||
10248 | internal PriorityQueue(Comparison<TPriority> comparison) : | ||
10249 | this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, comparison) { } | ||
10250 | internal PriorityQueue(int capacity, IComparer<TPriority> comparer) : | ||
10251 | this(capacity, new Comparison<TPriority>(comparer.Compare)) { } | ||
10252 | internal PriorityQueue(int capacity, Comparison<TPriority> comparison) | ||
10253 | { | ||
10254 | m_lookupTable = new Dictionary<uint, LookupItem>(capacity); | ||
10255 | |||
10256 | for (int i = 0; i < m_heaps.Length; ++i) | ||
10257 | m_heaps[i] = new MinHeap<MinHeapItem>(capacity); | ||
10258 | this.m_comparison = comparison; | ||
10259 | } | ||
10260 | |||
10261 | internal object SyncRoot { get { return this.m_syncRoot; } } | ||
10262 | internal int Count | ||
10263 | { | ||
10264 | get | ||
10265 | { | ||
10266 | int count = 0; | ||
10267 | for (int i = 0; i < m_heaps.Length; ++i) | ||
10268 | count = m_heaps[i].Count; | ||
10269 | return count; | ||
10270 | } | ||
10271 | } | ||
10272 | |||
10273 | internal bool Enqueue(TPriority priority, TValue value, uint local_id) | ||
10274 | { | ||
10275 | LookupItem item; | ||
10276 | |||
10277 | if (m_lookupTable.TryGetValue(local_id, out item)) | ||
10278 | { | ||
10279 | item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison); | ||
10280 | return false; | ||
10281 | } | ||
10282 | else | ||
10283 | { | ||
10284 | item.Heap = m_heaps[0]; | ||
10285 | item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle); | ||
10286 | m_lookupTable.Add(local_id, item); | ||
10287 | return true; | ||
10288 | } | ||
10289 | } | ||
10290 | |||
10291 | internal TValue Peek() | ||
10292 | { | ||
10293 | for (int i = 0; i < m_heaps.Length; ++i) | ||
10294 | if (m_heaps[i].Count > 0) | ||
10295 | return m_heaps[i].Min().Value; | ||
10296 | throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); | ||
10297 | } | ||
10298 | |||
10299 | internal TValue Dequeue() | ||
10300 | { | ||
10301 | for (int i = 0; i < m_heaps.Length; ++i) | ||
10302 | { | ||
10303 | if (m_heaps[i].Count > 0) | ||
10304 | { | ||
10305 | MinHeapItem item = m_heaps[i].RemoveMin(); | ||
10306 | m_lookupTable.Remove(item.LocalID); | ||
10307 | return item.Value; | ||
10308 | } | ||
10309 | } | ||
10310 | throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); | ||
10311 | } | ||
10312 | |||
10313 | internal void Reprioritize(UpdatePriorityHandler handler) | ||
10314 | { | ||
10315 | MinHeapItem item; | ||
10316 | TPriority priority; | ||
10317 | |||
10318 | foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values)) | ||
10319 | { | ||
10320 | if (lookup.Heap.TryGetValue(lookup.Handle, out item)) | ||
10321 | { | ||
10322 | priority = item.Priority; | ||
10323 | if (handler(ref priority, item.LocalID)) | ||
10324 | { | ||
10325 | if (lookup.Heap.ContainsHandle(lookup.Handle)) | ||
10326 | lookup.Heap[lookup.Handle] = | ||
10327 | new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison); | ||
10328 | } | ||
10329 | else | ||
10330 | { | ||
10331 | m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update"); | ||
10332 | lookup.Heap.Remove(lookup.Handle); | ||
10333 | this.m_lookupTable.Remove(item.LocalID); | ||
10334 | } | ||
10335 | } | ||
10336 | } | ||
10337 | } | ||
10338 | |||
10339 | #region MinHeapItem | ||
10340 | private struct MinHeapItem : IComparable<MinHeapItem> | ||
10341 | { | ||
10342 | private TPriority priority; | ||
10343 | private TValue value; | ||
10344 | private uint local_id; | ||
10345 | private Comparison<TPriority> comparison; | ||
10346 | |||
10347 | internal MinHeapItem(TPriority priority, TValue value, uint local_id) : | ||
10348 | this(priority, value, local_id, Comparer<TPriority>.Default) { } | ||
10349 | internal MinHeapItem(TPriority priority, TValue value, uint local_id, IComparer<TPriority> comparer) : | ||
10350 | this(priority, value, local_id, new Comparison<TPriority>(comparer.Compare)) { } | ||
10351 | internal MinHeapItem(TPriority priority, TValue value, uint local_id, Comparison<TPriority> comparison) | ||
10352 | { | ||
10353 | this.priority = priority; | ||
10354 | this.value = value; | ||
10355 | this.local_id = local_id; | ||
10356 | this.comparison = comparison; | ||
10357 | } | ||
10358 | |||
10359 | internal TPriority Priority { get { return this.priority; } } | ||
10360 | internal TValue Value { get { return this.value; } } | ||
10361 | internal uint LocalID { get { return this.local_id; } } | ||
10362 | |||
10363 | public override string ToString() | ||
10364 | { | ||
10365 | StringBuilder sb = new StringBuilder(); | ||
10366 | sb.Append("["); | ||
10367 | if (this.priority != null) | ||
10368 | sb.Append(this.priority.ToString()); | ||
10369 | sb.Append(","); | ||
10370 | if (this.value != null) | ||
10371 | sb.Append(this.value.ToString()); | ||
10372 | sb.Append("]"); | ||
10373 | return sb.ToString(); | ||
10374 | } | ||
10375 | |||
10376 | public int CompareTo(MinHeapItem other) | ||
10377 | { | ||
10378 | return this.comparison(this.priority, other.priority); | ||
10379 | } | ||
10380 | } | ||
10381 | #endregion | ||
10382 | |||
10383 | #region LookupItem | ||
10384 | private struct LookupItem | ||
10385 | { | ||
10386 | internal MinHeap<MinHeapItem> Heap; | ||
10387 | internal IHandle Handle; | ||
10388 | } | ||
10389 | #endregion | ||
10390 | } | ||
10391 | #endregion | ||
10392 | |||
10374 | } | 10393 | } |
10375 | } | 10394 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs index d25bf95..938cf50 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | |||
@@ -51,7 +51,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
51 | 51 | ||
52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
53 | private bool m_shuttingdown; | 53 | private bool m_shuttingdown; |
54 | private long m_lastloopprocessed; | ||
55 | private AssetBase m_missingImage; | 54 | private AssetBase m_missingImage; |
56 | private LLClientView m_client; //Client we're assigned to | 55 | private LLClientView m_client; //Client we're assigned to |
57 | private IAssetService m_assetCache; //Asset Cache | 56 | private IAssetService m_assetCache; //Asset Cache |
@@ -169,7 +168,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
169 | 168 | ||
170 | public bool ProcessImageQueue(int packetsToSend) | 169 | public bool ProcessImageQueue(int packetsToSend) |
171 | { | 170 | { |
172 | m_lastloopprocessed = DateTime.Now.Ticks; | ||
173 | int packetsSent = 0; | 171 | int packetsSent = 0; |
174 | 172 | ||
175 | while (packetsSent < packetsToSend) | 173 | while (packetsSent < packetsToSend) |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 4eee6b6..a9bc7d2 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -33,6 +33,8 @@ using OpenSim.Framework; | |||
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.Packets; | 34 | using OpenMetaverse.Packets; |
35 | 35 | ||
36 | using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; | ||
37 | |||
36 | namespace OpenSim.Region.ClientStack.LindenUDP | 38 | namespace OpenSim.Region.ClientStack.LindenUDP |
37 | { | 39 | { |
38 | #region Delegates | 40 | #region Delegates |
@@ -48,11 +50,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
48 | /// are waiting on ACKs for</param> | 50 | /// are waiting on ACKs for</param> |
49 | public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); | 51 | public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); |
50 | /// <summary> | 52 | /// <summary> |
51 | /// Fired when the queue for a packet category is empty. This event can be | 53 | /// Fired when the queue for one or more packet categories is empty. This |
52 | /// hooked to put more data on the empty queue | 54 | /// event can be hooked to put more data on the empty queues |
53 | /// </summary> | 55 | /// </summary> |
54 | /// <param name="category">Category of the packet queue that is empty</param> | 56 | /// <param name="category">Categories of the packet queues that are empty</param> |
55 | public delegate void QueueEmpty(ThrottleOutPacketType category); | 57 | public delegate void QueueEmpty(ThrottleOutPacketTypeFlags categories); |
56 | 58 | ||
57 | #endregion Delegates | 59 | #endregion Delegates |
58 | 60 | ||
@@ -98,12 +100,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
98 | /// <summary>True when this connection is alive, otherwise false</summary> | 100 | /// <summary>True when this connection is alive, otherwise false</summary> |
99 | public bool IsConnected = true; | 101 | public bool IsConnected = true; |
100 | /// <summary>True when this connection is paused, otherwise false</summary> | 102 | /// <summary>True when this connection is paused, otherwise false</summary> |
101 | public bool IsPaused = true; | 103 | public bool IsPaused; |
102 | /// <summary>Environment.TickCount when the last packet was received for this client</summary> | 104 | /// <summary>Environment.TickCount when the last packet was received for this client</summary> |
103 | public int TickLastPacketReceived; | 105 | public int TickLastPacketReceived; |
104 | 106 | ||
105 | /// <summary>Timer granularity. This is set to the measured resolution of Environment.TickCount</summary> | ||
106 | public readonly float G; | ||
107 | /// <summary>Smoothed round-trip time. A smoothed average of the round-trip time for sending a | 107 | /// <summary>Smoothed round-trip time. A smoothed average of the round-trip time for sending a |
108 | /// reliable packet to the client and receiving an ACK</summary> | 108 | /// reliable packet to the client and receiving an ACK</summary> |
109 | public float SRTT; | 109 | public float SRTT; |
@@ -128,6 +128,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
128 | private int m_packetsReceivedReported; | 128 | private int m_packetsReceivedReported; |
129 | /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary> | 129 | /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary> |
130 | private int m_packetsSentReported; | 130 | private int m_packetsSentReported; |
131 | /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary> | ||
132 | private int m_nextOnQueueEmpty = 1; | ||
131 | 133 | ||
132 | /// <summary>Throttle bucket for this agent's connection</summary> | 134 | /// <summary>Throttle bucket for this agent's connection</summary> |
133 | private readonly TokenBucket m_throttle; | 135 | private readonly TokenBucket m_throttle; |
@@ -140,9 +142,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
140 | /// <summary>A container that can hold one packet for each outbox, used to store | 142 | /// <summary>A container that can hold one packet for each outbox, used to store |
141 | /// dequeued packets that are being held for throttling</summary> | 143 | /// dequeued packets that are being held for throttling</summary> |
142 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | 144 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; |
143 | /// <summary>Flags to prevent queue empty callbacks from stacking up on | ||
144 | /// top of each other</summary> | ||
145 | private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT]; | ||
146 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> | 145 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> |
147 | private readonly LLUDPServer m_udpServer; | 146 | private readonly LLUDPServer m_udpServer; |
148 | 147 | ||
@@ -163,26 +162,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
163 | CircuitCode = circuitCode; | 162 | CircuitCode = circuitCode; |
164 | m_udpServer = server; | 163 | m_udpServer = server; |
165 | m_defaultThrottleRates = rates; | 164 | m_defaultThrottleRates = rates; |
165 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | ||
166 | m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); | 166 | m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); |
167 | // Create an array of token buckets for this clients different throttle categories | ||
167 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 168 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
168 | 169 | ||
169 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 170 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
170 | { | 171 | { |
171 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 172 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; |
172 | 173 | ||
174 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | ||
173 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | 175 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
176 | // 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)); | 177 | m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); |
175 | } | 178 | } |
176 | 179 | ||
177 | // Set the granularity variable used for retransmission calculations to | ||
178 | // the measured resolution of Environment.TickCount | ||
179 | G = server.TickCountResolution; | ||
180 | |||
181 | // Default the retransmission timeout to three seconds | 180 | // Default the retransmission timeout to three seconds |
182 | RTO = 3000; | 181 | RTO = 3000; |
183 | 182 | ||
184 | // Initialize this to a sane value to prevent early disconnects | 183 | // Initialize this to a sane value to prevent early disconnects |
185 | TickLastPacketReceived = Environment.TickCount; | 184 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; |
186 | } | 185 | } |
187 | 186 | ||
188 | /// <summary> | 187 | /// <summary> |
@@ -191,7 +190,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
191 | public void Shutdown() | 190 | public void Shutdown() |
192 | { | 191 | { |
193 | IsConnected = false; | 192 | IsConnected = false; |
194 | NeedAcks.Clear(); | ||
195 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 193 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
196 | { | 194 | { |
197 | m_packetOutboxes[i].Clear(); | 195 | m_packetOutboxes[i].Clear(); |
@@ -293,36 +291,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
293 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); | 291 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); |
294 | task -= state; | 292 | task -= state; |
295 | 293 | ||
296 | int ceiling = Int32.MaxValue; | 294 | // Make sure none of the throttles are set below our packet MTU, |
297 | if (m_defaultThrottleRates.Total != 0) | 295 | // otherwise a throttle could become permanently clogged |
298 | { | 296 | resend = Math.Max(resend, LLUDPServer.MTU); |
299 | ceiling = m_defaultThrottleRates.Total; | 297 | land = Math.Max(land, LLUDPServer.MTU); |
300 | if (ceiling < Packet.MTU) ceiling = Packet.MTU; | 298 | wind = Math.Max(wind, LLUDPServer.MTU); |
301 | } | 299 | cloud = Math.Max(cloud, LLUDPServer.MTU); |
302 | 300 | task = Math.Max(task, LLUDPServer.MTU); | |
303 | resend = Utils.Clamp(resend, Packet.MTU, ceiling); | 301 | texture = Math.Max(texture, LLUDPServer.MTU); |
304 | land = Utils.Clamp(land, Packet.MTU, ceiling); | 302 | asset = Math.Max(asset, LLUDPServer.MTU); |
305 | wind = Utils.Clamp(wind, Packet.MTU, ceiling); | 303 | state = Math.Max(state, LLUDPServer.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 | 304 | ||
312 | int total = resend + land + wind + cloud + task + texture + asset + state; | 305 | int total = resend + land + wind + cloud + task + texture + asset + state; |
313 | int taskTotal = task + state; | ||
314 | 306 | ||
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}", | 307 | 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); | 308 | AgentID, resend, land, wind, cloud, task, texture, asset, state, total); |
317 | 309 | ||
318 | SetThrottle(ThrottleOutPacketType.Resend, resend, resend); | 310 | // Update the token buckets with new throttle values |
319 | SetThrottle(ThrottleOutPacketType.Land, land, land); | 311 | TokenBucket bucket; |
320 | SetThrottle(ThrottleOutPacketType.Wind, wind, wind); | 312 | |
321 | SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud); | 313 | bucket = m_throttle; |
322 | SetThrottle(ThrottleOutPacketType.Task, task, taskTotal); | 314 | bucket.MaxBurst = total; |
323 | SetThrottle(ThrottleOutPacketType.Texture, texture, texture); | 315 | |
324 | SetThrottle(ThrottleOutPacketType.Asset, asset, asset); | 316 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; |
325 | SetThrottle(ThrottleOutPacketType.State, state, taskTotal); | 317 | bucket.DripRate = resend; |
318 | bucket.MaxBurst = resend; | ||
319 | |||
320 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; | ||
321 | bucket.DripRate = land; | ||
322 | bucket.MaxBurst = land; | ||
323 | |||
324 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; | ||
325 | bucket.DripRate = wind; | ||
326 | bucket.MaxBurst = wind; | ||
327 | |||
328 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; | ||
329 | bucket.DripRate = cloud; | ||
330 | bucket.MaxBurst = cloud; | ||
331 | |||
332 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; | ||
333 | bucket.DripRate = asset; | ||
334 | bucket.MaxBurst = asset; | ||
335 | |||
336 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; | ||
337 | bucket.DripRate = task + state; | ||
338 | bucket.MaxBurst = task + state; | ||
339 | |||
340 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; | ||
341 | bucket.DripRate = state; | ||
342 | bucket.MaxBurst = state; | ||
343 | |||
344 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; | ||
345 | bucket.DripRate = texture; | ||
346 | bucket.MaxBurst = texture; | ||
326 | } | 347 | } |
327 | 348 | ||
328 | public byte[] GetThrottlesPacked() | 349 | public byte[] GetThrottlesPacked() |
@@ -342,17 +363,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
342 | return data; | 363 | return data; |
343 | } | 364 | } |
344 | 365 | ||
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) | 366 | public bool EnqueueOutgoing(OutgoingPacket packet) |
357 | { | 367 | { |
358 | int category = (int)packet.Category; | 368 | int category = (int)packet.Category; |
@@ -394,10 +404,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
394 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; | 404 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; |
395 | TokenBucket bucket; | 405 | TokenBucket bucket; |
396 | bool packetSent = false; | 406 | bool packetSent = false; |
407 | ThrottleOutPacketTypeFlags emptyCategories = 0; | ||
408 | |||
409 | //string queueDebugOutput = String.Empty; // Serious debug business | ||
397 | 410 | ||
398 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 411 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
399 | { | 412 | { |
400 | bucket = m_throttleCategories[i]; | 413 | bucket = m_throttleCategories[i]; |
414 | //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business | ||
401 | 415 | ||
402 | if (m_nextPackets[i] != null) | 416 | if (m_nextPackets[i] != null) |
403 | { | 417 | { |
@@ -438,17 +452,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
438 | // empty callback now so it has a chance to fill before we | 452 | // empty callback now so it has a chance to fill before we |
439 | // get back here | 453 | // get back here |
440 | if (queue.Count == 0) | 454 | if (queue.Count == 0) |
441 | BeginFireQueueEmpty(i); | 455 | emptyCategories |= CategoryToFlag(i); |
442 | } | 456 | } |
443 | else | 457 | else |
444 | { | 458 | { |
445 | // No packets in this queue. Fire the queue empty callback | 459 | // No packets in this queue. Fire the queue empty callback |
446 | // if it has not been called recently | 460 | // if it has not been called recently |
447 | BeginFireQueueEmpty(i); | 461 | emptyCategories |= CategoryToFlag(i); |
448 | } | 462 | } |
449 | } | 463 | } |
450 | } | 464 | } |
451 | 465 | ||
466 | if (emptyCategories != 0) | ||
467 | BeginFireQueueEmpty(emptyCategories); | ||
468 | |||
469 | //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business | ||
452 | return packetSent; | 470 | return packetSent; |
453 | } | 471 | } |
454 | 472 | ||
@@ -479,8 +497,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
479 | SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r; | 497 | SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r; |
480 | } | 498 | } |
481 | 499 | ||
482 | // Always round retransmission timeout up to two seconds | 500 | RTO = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); |
483 | RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); | 501 | |
502 | // Clamp the retransmission timeout to manageable values | ||
503 | RTO = Utils.Clamp(RTO, 3000, 10000); | ||
504 | |||
484 | //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + | 505 | //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + |
485 | // RTTVAR + " based on new RTT of " + r + "ms"); | 506 | // RTTVAR + " based on new RTT of " + r + "ms"); |
486 | } | 507 | } |
@@ -491,33 +512,89 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
491 | /// </summary> | 512 | /// </summary> |
492 | /// <param name="throttleIndex">Throttle category to fire the callback | 513 | /// <param name="throttleIndex">Throttle category to fire the callback |
493 | /// for</param> | 514 | /// for</param> |
494 | private void BeginFireQueueEmpty(int throttleIndex) | 515 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) |
495 | { | 516 | { |
496 | if (!m_onQueueEmptyRunning[throttleIndex]) | 517 | if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) |
497 | Util.FireAndForget(FireQueueEmpty, throttleIndex); | 518 | { |
519 | // Use a value of 0 to signal that FireQueueEmpty is running | ||
520 | m_nextOnQueueEmpty = 0; | ||
521 | // Asynchronously run the callback | ||
522 | Util.FireAndForget(FireQueueEmpty, categories); | ||
523 | } | ||
498 | } | 524 | } |
499 | 525 | ||
500 | /// <summary> | 526 | /// <summary> |
501 | /// Checks to see if this queue empty callback is already running, | 527 | /// Fires the OnQueueEmpty callback and sets the minimum time that it |
502 | /// then firing the event | 528 | /// can be called again |
503 | /// </summary> | 529 | /// </summary> |
504 | /// <param name="o">Throttle category to fire the callback for, stored | 530 | /// <param name="o">Throttle categories to fire the callback for, |
505 | /// as an object to match the WaitCallback delegate signature</param> | 531 | /// stored as an object to match the WaitCallback delegate |
532 | /// signature</param> | ||
506 | private void FireQueueEmpty(object o) | 533 | private void FireQueueEmpty(object o) |
507 | { | 534 | { |
508 | int i = (int)o; | 535 | const int MIN_CALLBACK_MS = 30; |
509 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 536 | |
537 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | ||
510 | QueueEmpty callback = OnQueueEmpty; | 538 | QueueEmpty callback = OnQueueEmpty; |
539 | |||
540 | int start = Environment.TickCount & Int32.MaxValue; | ||
511 | 541 | ||
512 | if (callback != null) | 542 | if (callback != null) |
513 | { | 543 | { |
514 | if (!m_onQueueEmptyRunning[i]) | 544 | try { callback(categories); } |
515 | { | 545 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } |
516 | m_onQueueEmptyRunning[i] = true; | 546 | } |
517 | try { callback(type); } | 547 | |
518 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } | 548 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; |
519 | m_onQueueEmptyRunning[i] = false; | 549 | if (m_nextOnQueueEmpty == 0) |
520 | } | 550 | m_nextOnQueueEmpty = 1; |
551 | } | ||
552 | |||
553 | /// <summary> | ||
554 | /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a | ||
555 | /// flag value | ||
556 | /// </summary> | ||
557 | /// <param name="i">Throttle category to convert</param> | ||
558 | /// <returns>Flag representation of the throttle category</returns> | ||
559 | private static ThrottleOutPacketTypeFlags CategoryToFlag(int i) | ||
560 | { | ||
561 | ThrottleOutPacketType category = (ThrottleOutPacketType)i; | ||
562 | |||
563 | /* | ||
564 | * Land = 1, | ||
565 | /// <summary>Wind data</summary> | ||
566 | Wind = 2, | ||
567 | /// <summary>Cloud data</summary> | ||
568 | Cloud = 3, | ||
569 | /// <summary>Any packets that do not fit into the other throttles</summary> | ||
570 | Task = 4, | ||
571 | /// <summary>Texture assets</summary> | ||
572 | Texture = 5, | ||
573 | /// <summary>Non-texture assets</summary> | ||
574 | Asset = 6, | ||
575 | /// <summary>Avatar and primitive data</summary> | ||
576 | /// <remarks>This is a sub-category of Task</remarks> | ||
577 | State = 7, | ||
578 | */ | ||
579 | |||
580 | switch (category) | ||
581 | { | ||
582 | case ThrottleOutPacketType.Land: | ||
583 | return ThrottleOutPacketTypeFlags.Land; | ||
584 | case ThrottleOutPacketType.Wind: | ||
585 | return ThrottleOutPacketTypeFlags.Wind; | ||
586 | case ThrottleOutPacketType.Cloud: | ||
587 | return ThrottleOutPacketTypeFlags.Cloud; | ||
588 | case ThrottleOutPacketType.Task: | ||
589 | return ThrottleOutPacketTypeFlags.Task; | ||
590 | case ThrottleOutPacketType.Texture: | ||
591 | return ThrottleOutPacketTypeFlags.Texture; | ||
592 | case ThrottleOutPacketType.Asset: | ||
593 | return ThrottleOutPacketTypeFlags.Asset; | ||
594 | case ThrottleOutPacketType.State: | ||
595 | return ThrottleOutPacketTypeFlags.State; | ||
596 | default: | ||
597 | return 0; | ||
521 | } | 598 | } |
522 | } | 599 | } |
523 | } | 600 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 545a0bc..a9f4b2c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -39,6 +39,8 @@ using OpenSim.Framework.Statistics; | |||
39 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenMetaverse; | 40 | using OpenMetaverse; |
41 | 41 | ||
42 | using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; | ||
43 | |||
42 | namespace OpenSim.Region.ClientStack.LindenUDP | 44 | namespace OpenSim.Region.ClientStack.LindenUDP |
43 | { | 45 | { |
44 | /// <summary> | 46 | /// <summary> |
@@ -89,8 +91,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
89 | /// </summary> | 91 | /// </summary> |
90 | public class LLUDPServer : OpenSimUDPBase | 92 | public class LLUDPServer : OpenSimUDPBase |
91 | { | 93 | { |
94 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | ||
95 | public const int MTU = 1400; | ||
96 | |||
92 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 97 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
93 | 98 | ||
99 | /// <summary>The measured resolution of Environment.TickCount</summary> | ||
100 | public readonly float TickCountResolution; | ||
101 | |||
94 | /// <summary>Handlers for incoming packets</summary> | 102 | /// <summary>Handlers for incoming packets</summary> |
95 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | 103 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); |
96 | /// <summary>Incoming packets that are awaiting handling</summary> | 104 | /// <summary>Incoming packets that are awaiting handling</summary> |
@@ -104,20 +112,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
104 | /// <summary>Manages authentication for agent circuits</summary> | 112 | /// <summary>Manages authentication for agent circuits</summary> |
105 | private AgentCircuitManager m_circuitManager; | 113 | private AgentCircuitManager m_circuitManager; |
106 | /// <summary>Reference to the scene this UDP server is attached to</summary> | 114 | /// <summary>Reference to the scene this UDP server is attached to</summary> |
107 | private IScene m_scene; | 115 | private Scene m_scene; |
108 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> | 116 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> |
109 | private Location m_location; | 117 | private Location m_location; |
110 | /// <summary>The measured resolution of Environment.TickCount</summary> | ||
111 | private float m_tickCountResolution; | ||
112 | /// <summary>The size of the receive buffer for the UDP socket. This value | 118 | /// <summary>The size of the receive buffer for the UDP socket. This value |
113 | /// is passed up to the operating system and used in the system networking | 119 | /// is passed up to the operating system and used in the system networking |
114 | /// stack. Use zero to leave this value as the default</summary> | 120 | /// stack. Use zero to leave this value as the default</summary> |
115 | private int m_recvBufferSize; | 121 | private int m_recvBufferSize; |
116 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | 122 | /// <summary>Flag to process packets asynchronously or synchronously</summary> |
117 | private bool m_asyncPacketHandling; | 123 | private bool m_asyncPacketHandling; |
124 | /// <summary>Tracks whether or not a packet was sent each round so we know | ||
125 | /// whether or not to sleep</summary> | ||
126 | private bool m_packetSent; | ||
127 | |||
128 | /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> | ||
129 | private int m_tickLastOutgoingPacketHandler; | ||
130 | /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> | ||
131 | private int m_elapsedMSOutgoingPacketHandler; | ||
132 | /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> | ||
133 | private int m_elapsed100MSOutgoingPacketHandler; | ||
134 | /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> | ||
135 | private int m_elapsed500MSOutgoingPacketHandler; | ||
136 | |||
137 | /// <summary>Flag to signal when clients should check for resends</summary> | ||
138 | private bool m_resendUnacked; | ||
139 | /// <summary>Flag to signal when clients should send ACKs</summary> | ||
140 | private bool m_sendAcks; | ||
141 | /// <summary>Flag to signal when clients should send pings</summary> | ||
142 | private bool m_sendPing; | ||
118 | 143 | ||
119 | /// <summary>The measured resolution of Environment.TickCount</summary> | ||
120 | public float TickCountResolution { get { return m_tickCountResolution; } } | ||
121 | public Socket Server { get { return null; } } | 144 | public Socket Server { get { return null; } } |
122 | 145 | ||
123 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 146 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) |
@@ -126,16 +149,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
126 | #region Environment.TickCount Measurement | 149 | #region Environment.TickCount Measurement |
127 | 150 | ||
128 | // Measure the resolution of Environment.TickCount | 151 | // Measure the resolution of Environment.TickCount |
129 | m_tickCountResolution = 0f; | 152 | TickCountResolution = 0f; |
130 | for (int i = 0; i < 5; i++) | 153 | for (int i = 0; i < 5; i++) |
131 | { | 154 | { |
132 | int start = Environment.TickCount; | 155 | int start = Environment.TickCount; |
133 | int now = start; | 156 | int now = start; |
134 | while (now == start) | 157 | while (now == start) |
135 | now = Environment.TickCount; | 158 | now = Environment.TickCount; |
136 | m_tickCountResolution += (float)(now - start) * 0.2f; | 159 | TickCountResolution += (float)(now - start) * 0.2f; |
137 | } | 160 | } |
138 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); | 161 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); |
162 | TickCountResolution = (float)Math.Ceiling(TickCountResolution); | ||
139 | 163 | ||
140 | #endregion Environment.TickCount Measurement | 164 | #endregion Environment.TickCount Measurement |
141 | 165 | ||
@@ -181,15 +205,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | 205 | ||
182 | public void AddScene(IScene scene) | 206 | public void AddScene(IScene scene) |
183 | { | 207 | { |
184 | if (m_scene == null) | 208 | if (m_scene != null) |
185 | { | 209 | { |
186 | m_scene = scene; | 210 | m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); |
187 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 211 | return; |
188 | } | 212 | } |
189 | else | 213 | |
214 | if (!(scene is Scene)) | ||
190 | { | 215 | { |
191 | m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); | 216 | m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType()); |
217 | return; | ||
192 | } | 218 | } |
219 | |||
220 | m_scene = (Scene)scene; | ||
221 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | ||
193 | } | 222 | } |
194 | 223 | ||
195 | public bool HandlesRegion(Location x) | 224 | public bool HandlesRegion(Location x) |
@@ -267,38 +296,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
267 | { | 296 | { |
268 | int dataLength = data.Length; | 297 | int dataLength = data.Length; |
269 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | 298 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; |
299 | bool doCopy = true; | ||
270 | 300 | ||
271 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. | 301 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. |
272 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting | 302 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting |
273 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here | 303 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here |
274 | // to accomodate for both common scenarios and provide ample room for ACK appending in both | 304 | // to accomodate for both common scenarios and provide ample room for ACK appending in both |
275 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; | 305 | int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; |
276 | 306 | ||
277 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); | 307 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
278 | 308 | ||
279 | // Zerocode if needed | 309 | // Zerocode if needed |
280 | if (doZerocode) | 310 | if (doZerocode) |
281 | { | 311 | { |
282 | try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); } | 312 | try |
313 | { | ||
314 | dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); | ||
315 | doCopy = false; | ||
316 | } | ||
283 | catch (IndexOutOfRangeException) | 317 | catch (IndexOutOfRangeException) |
284 | { | 318 | { |
285 | // The packet grew larger than the bufferSize while zerocoding. | 319 | // The packet grew larger than the bufferSize while zerocoding. |
286 | // Remove the MSG_ZEROCODED flag and send the unencoded data | 320 | // Remove the MSG_ZEROCODED flag and send the unencoded data |
287 | // instead | 321 | // instead |
288 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); | 322 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + |
323 | " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); | ||
289 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); | 324 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); |
290 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
291 | } | 325 | } |
292 | } | 326 | } |
293 | else | 327 | |
328 | // If the packet data wasn't already copied during zerocoding, copy it now | ||
329 | if (doCopy) | ||
294 | { | 330 | { |
295 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 331 | if (dataLength <= buffer.Data.Length) |
332 | { | ||
333 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
334 | } | ||
335 | else | ||
336 | { | ||
337 | m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + | ||
338 | type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); | ||
339 | return; | ||
340 | } | ||
296 | } | 341 | } |
342 | |||
297 | buffer.DataLength = dataLength; | 343 | buffer.DataLength = dataLength; |
298 | 344 | ||
299 | #region Queue or Send | 345 | #region Queue or Send |
300 | 346 | ||
301 | // Look up the UDPClient this is going to | ||
302 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); | 347 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
303 | 348 | ||
304 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 349 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
@@ -338,57 +383,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
338 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); | 383 | StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); |
339 | pc.Header.Reliable = false; | 384 | pc.Header.Reliable = false; |
340 | 385 | ||
341 | OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest(); | ||
342 | |||
343 | pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; | 386 | pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; |
344 | pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; | 387 | // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit |
388 | pc.PingID.OldestUnacked = 0; | ||
345 | 389 | ||
346 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); | 390 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); |
347 | } | 391 | } |
348 | 392 | ||
349 | public void ResendUnacked(LLUDPClient udpClient) | 393 | public void ResendUnacked(LLUDPClient udpClient) |
350 | { | 394 | { |
351 | if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0) | 395 | if (!udpClient.IsConnected) |
396 | return; | ||
397 | |||
398 | // Disconnect an agent if no packets are received for some time | ||
399 | //FIXME: Make 60 an .ini setting | ||
400 | if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60) | ||
352 | { | 401 | { |
353 | // Disconnect an agent if no packets are received for some time | 402 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); |
354 | //FIXME: Make 60 an .ini setting | ||
355 | if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) | ||
356 | { | ||
357 | m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); | ||
358 | 403 | ||
359 | RemoveClient(udpClient); | 404 | RemoveClient(udpClient); |
360 | return; | 405 | return; |
361 | } | 406 | } |
362 | 407 | ||
363 | // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO | 408 | // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO |
364 | List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); | 409 | List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); |
365 | 410 | ||
366 | if (expiredPackets != null) | 411 | if (expiredPackets != null) |
367 | { | 412 | { |
368 | // Resend packets | 413 | m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); |
369 | for (int i = 0; i < expiredPackets.Count; i++) | ||
370 | { | ||
371 | OutgoingPacket outgoingPacket = expiredPackets[i]; | ||
372 | 414 | ||
373 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", | 415 | // Resend packets |
374 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); | 416 | for (int i = 0; i < expiredPackets.Count; i++) |
417 | { | ||
418 | OutgoingPacket outgoingPacket = expiredPackets[i]; | ||
375 | 419 | ||
376 | // Set the resent flag | 420 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", |
377 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); | 421 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); |
378 | outgoingPacket.Category = ThrottleOutPacketType.Resend; | ||
379 | 422 | ||
380 | // The TickCount will be set to the current time when the packet | 423 | // Set the resent flag |
381 | // is actually sent out again | 424 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); |
382 | outgoingPacket.TickCount = 0; | 425 | outgoingPacket.Category = ThrottleOutPacketType.Resend; |
383 | 426 | ||
384 | // Bump up the resend count on this packet | 427 | // Bump up the resend count on this packet |
385 | Interlocked.Increment(ref outgoingPacket.ResendCount); | 428 | Interlocked.Increment(ref outgoingPacket.ResendCount); |
386 | //Interlocked.Increment(ref Stats.ResentPackets); | 429 | //Interlocked.Increment(ref Stats.ResentPackets); |
387 | 430 | ||
388 | // Requeue or resend the packet | 431 | // Requeue or resend the packet |
389 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 432 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
390 | SendPacketFinal(outgoingPacket); | 433 | SendPacketFinal(outgoingPacket); |
391 | } | ||
392 | } | 434 | } |
393 | } | 435 | } |
394 | } | 436 | } |
@@ -409,9 +451,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
409 | if (!udpClient.IsConnected) | 451 | if (!udpClient.IsConnected) |
410 | return; | 452 | return; |
411 | 453 | ||
412 | // Keep track of when this packet was sent out (right now) | ||
413 | outgoingPacket.TickCount = Environment.TickCount; | ||
414 | |||
415 | #region ACK Appending | 454 | #region ACK Appending |
416 | 455 | ||
417 | int dataLength = buffer.DataLength; | 456 | int dataLength = buffer.DataLength; |
@@ -464,6 +503,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
464 | 503 | ||
465 | // Put the UDP payload on the wire | 504 | // Put the UDP payload on the wire |
466 | AsyncBeginSend(buffer); | 505 | AsyncBeginSend(buffer); |
506 | |||
507 | // Keep track of when this packet was sent out (right now) | ||
508 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | ||
467 | } | 509 | } |
468 | 510 | ||
469 | protected override void PacketReceived(UDPPacketBuffer buffer) | 511 | protected override void PacketReceived(UDPPacketBuffer buffer) |
@@ -506,14 +548,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
506 | // UseCircuitCode handling | 548 | // UseCircuitCode handling |
507 | if (packet.Type == PacketType.UseCircuitCode) | 549 | if (packet.Type == PacketType.UseCircuitCode) |
508 | { | 550 | { |
509 | AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint); | 551 | Util.FireAndForget( |
552 | delegate(object o) | ||
553 | { | ||
554 | IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; | ||
555 | |||
556 | // Begin the process of adding the client to the simulator | ||
557 | AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint); | ||
558 | |||
559 | // Acknowledge the UseCircuitCode packet | ||
560 | SendAckImmediate(remoteEndPoint, packet.Header.Sequence); | ||
561 | } | ||
562 | ); | ||
563 | return; | ||
510 | } | 564 | } |
511 | 565 | ||
512 | // Determine which agent this packet came from | 566 | // Determine which agent this packet came from |
513 | IClientAPI client; | 567 | IClientAPI client; |
514 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) | 568 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) |
515 | { | 569 | { |
516 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + | 570 | 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"); | 571 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); |
518 | return; | 572 | return; |
519 | } | 573 | } |
@@ -528,19 +582,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
528 | // Stats tracking | 582 | // Stats tracking |
529 | Interlocked.Increment(ref udpClient.PacketsReceived); | 583 | Interlocked.Increment(ref udpClient.PacketsReceived); |
530 | 584 | ||
531 | #region ACK Receiving | 585 | int now = Environment.TickCount & Int32.MaxValue; |
532 | |||
533 | int now = Environment.TickCount; | ||
534 | udpClient.TickLastPacketReceived = now; | 586 | udpClient.TickLastPacketReceived = now; |
535 | 587 | ||
588 | #region ACK Receiving | ||
589 | |||
536 | // Handle appended ACKs | 590 | // Handle appended ACKs |
537 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | 591 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) |
538 | { | 592 | { |
539 | lock (udpClient.NeedAcks.SyncRoot) | 593 | for (int i = 0; i < packet.Header.AckList.Length; i++) |
540 | { | 594 | udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent); |
541 | for (int i = 0; i < packet.Header.AckList.Length; i++) | ||
542 | AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent); | ||
543 | } | ||
544 | } | 595 | } |
545 | 596 | ||
546 | // Handle PacketAck packets | 597 | // Handle PacketAck packets |
@@ -548,11 +599,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
548 | { | 599 | { |
549 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | 600 | PacketAckPacket ackPacket = (PacketAckPacket)packet; |
550 | 601 | ||
551 | lock (udpClient.NeedAcks.SyncRoot) | 602 | for (int i = 0; i < ackPacket.Packets.Length; i++) |
552 | { | 603 | udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent); |
553 | for (int i = 0; i < ackPacket.Packets.Length; i++) | 604 | |
554 | AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); | 605 | // We don't need to do anything else with PacketAck packets |
555 | } | 606 | return; |
556 | } | 607 | } |
557 | 608 | ||
558 | #endregion ACK Receiving | 609 | #endregion ACK Receiving |
@@ -560,20 +611,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
560 | #region ACK Sending | 611 | #region ACK Sending |
561 | 612 | ||
562 | if (packet.Header.Reliable) | 613 | if (packet.Header.Reliable) |
614 | { | ||
563 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); | 615 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); |
564 | 616 | ||
565 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, | 617 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, |
566 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove | 618 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove |
567 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to | 619 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to |
568 | // client.BytesSinceLastACK. Lockless thread safety | 620 | // client.BytesSinceLastACK. Lockless thread safety |
569 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); | 621 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); |
570 | bytesSinceLastACK += buffer.DataLength; | 622 | bytesSinceLastACK += buffer.DataLength; |
571 | if (bytesSinceLastACK > Packet.MTU * 2) | 623 | if (bytesSinceLastACK > LLUDPServer.MTU * 2) |
572 | { | 624 | { |
573 | bytesSinceLastACK -= Packet.MTU * 2; | 625 | bytesSinceLastACK -= LLUDPServer.MTU * 2; |
574 | SendAcks(udpClient); | 626 | SendAcks(udpClient); |
627 | } | ||
628 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); | ||
575 | } | 629 | } |
576 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); | ||
577 | 630 | ||
578 | #endregion ACK Sending | 631 | #endregion ACK Sending |
579 | 632 | ||
@@ -593,16 +646,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
593 | 646 | ||
594 | #endregion Incoming Packet Accounting | 647 | #endregion Incoming Packet Accounting |
595 | 648 | ||
596 | // Don't bother clogging up the queue with PacketAck packets that are already handled here | 649 | #region Ping Check Handling |
597 | if (packet.Type != PacketType.PacketAck) | 650 | |
651 | if (packet.Type == PacketType.StartPingCheck) | ||
598 | { | 652 | { |
599 | // Inbox insertion | 653 | // We don't need to do anything else with ping checks |
600 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); | 654 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; |
655 | |||
656 | CompletePingCheckPacket completePing = new CompletePingCheckPacket(); | ||
657 | completePing.PingID.PingID = startPing.PingID.PingID; | ||
658 | SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); | ||
659 | return; | ||
601 | } | 660 | } |
661 | else if (packet.Type == PacketType.CompletePingCheck) | ||
662 | { | ||
663 | // We don't currently track client ping times | ||
664 | return; | ||
665 | } | ||
666 | |||
667 | #endregion Ping Check Handling | ||
668 | |||
669 | // Inbox insertion | ||
670 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); | ||
602 | } | 671 | } |
603 | 672 | ||
604 | protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) | 673 | private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) |
605 | { | 674 | { |
675 | PacketAckPacket ack = new PacketAckPacket(); | ||
676 | ack.Header.Reliable = false; | ||
677 | ack.Packets = new PacketAckPacket.PacketsBlock[1]; | ||
678 | ack.Packets[0] = new PacketAckPacket.PacketsBlock(); | ||
679 | ack.Packets[0].ID = sequenceNumber; | ||
680 | |||
681 | byte[] packetData = ack.ToBytes(); | ||
682 | int length = packetData.Length; | ||
683 | |||
684 | UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length); | ||
685 | buffer.DataLength = length; | ||
686 | |||
687 | Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); | ||
688 | |||
689 | AsyncBeginSend(buffer); | ||
606 | } | 690 | } |
607 | 691 | ||
608 | private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) | 692 | private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) |
@@ -672,33 +756,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
672 | client.Close(); | 756 | client.Close(); |
673 | } | 757 | } |
674 | 758 | ||
675 | private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) | ||
676 | { | ||
677 | OutgoingPacket ackedPacket; | ||
678 | if (client.NeedAcks.RemoveUnsafe(ack, out ackedPacket) && !fromResend) | ||
679 | { | ||
680 | // Update stats | ||
681 | Interlocked.Add(ref client.UnackedBytes, -ackedPacket.Buffer.DataLength); | ||
682 | |||
683 | // Calculate the round-trip time for this packet and its ACK | ||
684 | int rtt = currentTime - ackedPacket.TickCount; | ||
685 | if (rtt > 0) | ||
686 | client.UpdateRoundTrip(rtt); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | private void IncomingPacketHandler() | 759 | private void IncomingPacketHandler() |
691 | { | 760 | { |
692 | // Set this culture for the thread that incoming packets are received | 761 | // Set this culture for the thread that incoming packets are received |
693 | // on to en-US to avoid number parsing issues | 762 | // on to en-US to avoid number parsing issues |
694 | Culture.SetCurrentCulture(); | 763 | Culture.SetCurrentCulture(); |
695 | 764 | ||
696 | IncomingPacket incomingPacket = null; | ||
697 | |||
698 | while (base.IsRunning) | 765 | while (base.IsRunning) |
699 | { | 766 | { |
700 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 767 | try |
701 | Util.FireAndForget(ProcessInPacket, incomingPacket); | 768 | { |
769 | IncomingPacket incomingPacket = null; | ||
770 | |||
771 | if (packetInbox.Dequeue(100, ref incomingPacket)) | ||
772 | Util.FireAndForget(ProcessInPacket, incomingPacket); | ||
773 | } | ||
774 | catch (Exception ex) | ||
775 | { | ||
776 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); | ||
777 | } | ||
702 | } | 778 | } |
703 | 779 | ||
704 | if (packetInbox.Count > 0) | 780 | if (packetInbox.Count > 0) |
@@ -712,68 +788,97 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
712 | // on to en-US to avoid number parsing issues | 788 | // on to en-US to avoid number parsing issues |
713 | Culture.SetCurrentCulture(); | 789 | Culture.SetCurrentCulture(); |
714 | 790 | ||
715 | int now = Environment.TickCount; | ||
716 | int elapsedMS = 0; | ||
717 | int elapsed100MS = 0; | ||
718 | int elapsed500MS = 0; | ||
719 | |||
720 | while (base.IsRunning) | 791 | while (base.IsRunning) |
721 | { | 792 | { |
722 | bool resendUnacked = false; | 793 | try |
723 | bool sendAcks = false; | 794 | { |
724 | bool sendPings = false; | 795 | m_packetSent = false; |
725 | bool packetSent = false; | ||
726 | 796 | ||
727 | elapsedMS += Environment.TickCount - now; | 797 | #region Update Timers |
728 | 798 | ||
729 | // Check for pending outgoing resends every 100ms | 799 | m_resendUnacked = false; |
730 | if (elapsedMS >= 100) | 800 | m_sendAcks = false; |
731 | { | 801 | m_sendPing = false; |
732 | resendUnacked = true; | 802 | |
733 | elapsedMS -= 100; | 803 | // Update elapsed time |
734 | ++elapsed100MS; | 804 | int thisTick = Environment.TickCount & Int32.MaxValue; |
805 | if (m_tickLastOutgoingPacketHandler > thisTick) | ||
806 | m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick); | ||
807 | else | ||
808 | m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler); | ||
809 | |||
810 | m_tickLastOutgoingPacketHandler = thisTick; | ||
811 | |||
812 | // Check for pending outgoing resends every 100ms | ||
813 | if (m_elapsedMSOutgoingPacketHandler >= 100) | ||
814 | { | ||
815 | m_resendUnacked = true; | ||
816 | m_elapsedMSOutgoingPacketHandler = 0; | ||
817 | m_elapsed100MSOutgoingPacketHandler += 1; | ||
818 | } | ||
819 | |||
820 | // Check for pending outgoing ACKs every 500ms | ||
821 | if (m_elapsed100MSOutgoingPacketHandler >= 5) | ||
822 | { | ||
823 | m_sendAcks = true; | ||
824 | m_elapsed100MSOutgoingPacketHandler = 0; | ||
825 | m_elapsed500MSOutgoingPacketHandler += 1; | ||
826 | } | ||
827 | |||
828 | // Send pings to clients every 5000ms | ||
829 | if (m_elapsed500MSOutgoingPacketHandler >= 10) | ||
830 | { | ||
831 | m_sendPing = true; | ||
832 | m_elapsed500MSOutgoingPacketHandler = 0; | ||
833 | } | ||
834 | |||
835 | #endregion Update Timers | ||
836 | |||
837 | // Handle outgoing packets, resends, acknowledgements, and pings for each | ||
838 | // client. m_packetSent will be set to true if a packet is sent | ||
839 | m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); | ||
840 | |||
841 | // If nothing was sent, sleep for the minimum amount of time before a | ||
842 | // token bucket could get more tokens | ||
843 | if (!m_packetSent) | ||
844 | Thread.Sleep((int)TickCountResolution); | ||
735 | } | 845 | } |
736 | // Check for pending outgoing ACKs every 500ms | 846 | catch (Exception ex) |
737 | if (elapsed100MS >= 5) | ||
738 | { | 847 | { |
739 | sendAcks = true; | 848 | m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex); |
740 | elapsed100MS = 0; | ||
741 | ++elapsed500MS; | ||
742 | } | 849 | } |
743 | // Send pings to clients every 5000ms | 850 | } |
744 | if (elapsed500MS >= 10) | 851 | } |
852 | |||
853 | private void ClientOutgoingPacketHandler(IClientAPI client) | ||
854 | { | ||
855 | try | ||
856 | { | ||
857 | if (client is LLClientView) | ||
745 | { | 858 | { |
746 | sendPings = true; | 859 | LLUDPClient udpClient = ((LLClientView)client).UDPClient; |
747 | elapsed500MS = 0; | ||
748 | } | ||
749 | 860 | ||
750 | m_scene.ClientManager.ForEach( | 861 | if (udpClient.IsConnected) |
751 | delegate(IClientAPI client) | ||
752 | { | 862 | { |
753 | if (client is LLClientView) | 863 | if (m_resendUnacked) |
754 | { | 864 | ResendUnacked(udpClient); |
755 | LLUDPClient udpClient = ((LLClientView)client).UDPClient; | 865 | |
756 | 866 | if (m_sendAcks) | |
757 | if (udpClient.IsConnected) | 867 | SendAcks(udpClient); |
758 | { | 868 | |
759 | if (udpClient.DequeueOutgoing()) | 869 | if (m_sendPing) |
760 | packetSent = true; | 870 | SendPing(udpClient); |
761 | if (resendUnacked) | ||
762 | ResendUnacked(udpClient); | ||
763 | if (sendAcks) | ||
764 | { | ||
765 | SendAcks(udpClient); | ||
766 | udpClient.SendPacketStats(); | ||
767 | } | ||
768 | if (sendPings) | ||
769 | SendPing(udpClient); | ||
770 | } | ||
771 | } | ||
772 | } | ||
773 | ); | ||
774 | 871 | ||
775 | if (!packetSent) | 872 | // Dequeue any outgoing packets that are within the throttle limits |
776 | Thread.Sleep(20); | 873 | if (udpClient.DequeueOutgoing()) |
874 | m_packetSent = true; | ||
875 | } | ||
876 | } | ||
877 | } | ||
878 | catch (Exception ex) | ||
879 | { | ||
880 | m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + | ||
881 | " threw an exception: " + ex.Message, ex); | ||
777 | } | 882 | } |
778 | } | 883 | } |
779 | 884 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs index d16837d..552cc4a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs | |||
@@ -45,13 +45,6 @@ namespace OpenMetaverse | |||
45 | /// </summary> | 45 | /// </summary> |
46 | /// <param name="buffer">Incoming packet buffer</param> | 46 | /// <param name="buffer">Incoming packet buffer</param> |
47 | protected abstract void PacketReceived(UDPPacketBuffer buffer); | 47 | protected abstract void PacketReceived(UDPPacketBuffer buffer); |
48 | |||
49 | /// <summary> | ||
50 | /// This method is called when an outgoing packet is sent | ||
51 | /// </summary> | ||
52 | /// <param name="buffer">Outgoing packet buffer</param> | ||
53 | /// <param name="bytesSent">Number of bytes written to the wire</param> | ||
54 | protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); | ||
55 | 48 | ||
56 | /// <summary>UDP port to bind to in server mode</summary> | 49 | /// <summary>UDP port to bind to in server mode</summary> |
57 | protected int m_udpPort; | 50 | protected int m_udpPort; |
@@ -279,8 +272,6 @@ namespace OpenMetaverse | |||
279 | { | 272 | { |
280 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | 273 | UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; |
281 | int bytesSent = m_udpSocket.EndSendTo(result); | 274 | int bytesSent = m_udpSocket.EndSendTo(result); |
282 | |||
283 | PacketSent(buf, bytesSent); | ||
284 | } | 275 | } |
285 | catch (SocketException) { } | 276 | catch (SocketException) { } |
286 | catch (ObjectDisposedException) { } | 277 | catch (ObjectDisposedException) { } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs new file mode 100644 index 0000000..bdbd284 --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// A hierarchical token bucket for bandwidth throttling. See | ||
34 | /// http://en.wikipedia.org/wiki/Token_bucket for more information | ||
35 | /// </summary> | ||
36 | public class TokenBucket | ||
37 | { | ||
38 | /// <summary>Parent bucket to this bucket, or null if this is a root | ||
39 | /// bucket</summary> | ||
40 | TokenBucket parent; | ||
41 | /// <summary>Size of the bucket in bytes. If zero, the bucket has | ||
42 | /// infinite capacity</summary> | ||
43 | int maxBurst; | ||
44 | /// <summary>Rate that the bucket fills, in bytes per millisecond. If | ||
45 | /// zero, the bucket always remains full</summary> | ||
46 | int tokensPerMS; | ||
47 | /// <summary>Number of tokens currently in the bucket</summary> | ||
48 | int content; | ||
49 | /// <summary>Time of the last drip, in system ticks</summary> | ||
50 | int lastDrip; | ||
51 | |||
52 | #region Properties | ||
53 | |||
54 | /// <summary> | ||
55 | /// The parent bucket of this bucket, or null if this bucket has no | ||
56 | /// parent. The parent bucket will limit the aggregate bandwidth of all | ||
57 | /// of its children buckets | ||
58 | /// </summary> | ||
59 | public TokenBucket Parent | ||
60 | { | ||
61 | get { return parent; } | ||
62 | } | ||
63 | |||
64 | /// <summary> | ||
65 | /// Maximum burst rate in bytes per second. This is the maximum number | ||
66 | /// of tokens that can accumulate in the bucket at any one time | ||
67 | /// </summary> | ||
68 | public int MaxBurst | ||
69 | { | ||
70 | get { return maxBurst; } | ||
71 | set { maxBurst = (value >= 0 ? value : 0); } | ||
72 | } | ||
73 | |||
74 | /// <summary> | ||
75 | /// The speed limit of this bucket in bytes per second. This is the | ||
76 | /// number of tokens that are added to the bucket per second | ||
77 | /// </summary> | ||
78 | /// <remarks>Tokens are added to the bucket any time | ||
79 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | ||
80 | /// the system tick interval (typically around 15-22ms)</remarks> | ||
81 | public int DripRate | ||
82 | { | ||
83 | get { return tokensPerMS * 1000; } | ||
84 | set | ||
85 | { | ||
86 | if (value == 0) | ||
87 | tokensPerMS = 0; | ||
88 | else | ||
89 | { | ||
90 | int bpms = (int)((float)value / 1000.0f); | ||
91 | |||
92 | if (bpms <= 0) | ||
93 | tokensPerMS = 1; // 1 byte/ms is the minimum granularity | ||
94 | else | ||
95 | tokensPerMS = bpms; | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /// <summary> | ||
101 | /// The speed limit of this bucket in bytes per millisecond | ||
102 | /// </summary> | ||
103 | public int DripPerMS | ||
104 | { | ||
105 | get { return tokensPerMS; } | ||
106 | } | ||
107 | |||
108 | /// <summary> | ||
109 | /// The number of bytes that can be sent at this moment. This is the | ||
110 | /// current number of tokens in the bucket | ||
111 | /// <remarks>If this bucket has a parent bucket that does not have | ||
112 | /// enough tokens for a request, <seealso cref="RemoveTokens"/> will | ||
113 | /// return false regardless of the content of this bucket</remarks> | ||
114 | /// </summary> | ||
115 | public int Content | ||
116 | { | ||
117 | get { return content; } | ||
118 | } | ||
119 | |||
120 | #endregion Properties | ||
121 | |||
122 | /// <summary> | ||
123 | /// Default constructor | ||
124 | /// </summary> | ||
125 | /// <param name="parent">Parent bucket if this is a child bucket, or | ||
126 | /// null if this is a root bucket</param> | ||
127 | /// <param name="maxBurst">Maximum size of the bucket in bytes, or | ||
128 | /// zero if this bucket has no maximum capacity</param> | ||
129 | /// <param name="dripRate">Rate that the bucket fills, in bytes per | ||
130 | /// second. If zero, the bucket always remains full</param> | ||
131 | public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) | ||
132 | { | ||
133 | this.parent = parent; | ||
134 | MaxBurst = maxBurst; | ||
135 | DripRate = dripRate; | ||
136 | lastDrip = Environment.TickCount & Int32.MaxValue; | ||
137 | } | ||
138 | |||
139 | /// <summary> | ||
140 | /// Remove a given number of tokens from the bucket | ||
141 | /// </summary> | ||
142 | /// <param name="amount">Number of tokens to remove from the bucket</param> | ||
143 | /// <returns>True if the requested number of tokens were removed from | ||
144 | /// the bucket, otherwise false</returns> | ||
145 | public bool RemoveTokens(int amount) | ||
146 | { | ||
147 | bool dummy; | ||
148 | return RemoveTokens(amount, out dummy); | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Remove a given number of tokens from the bucket | ||
153 | /// </summary> | ||
154 | /// <param name="amount">Number of tokens to remove from the bucket</param> | ||
155 | /// <param name="dripSucceeded">True if tokens were added to the bucket | ||
156 | /// during this call, otherwise false</param> | ||
157 | /// <returns>True if the requested number of tokens were removed from | ||
158 | /// the bucket, otherwise false</returns> | ||
159 | public bool RemoveTokens(int amount, out bool dripSucceeded) | ||
160 | { | ||
161 | if (maxBurst == 0) | ||
162 | { | ||
163 | dripSucceeded = true; | ||
164 | return true; | ||
165 | } | ||
166 | |||
167 | dripSucceeded = Drip(); | ||
168 | |||
169 | if (content - amount >= 0) | ||
170 | { | ||
171 | if (parent != null && !parent.RemoveTokens(amount)) | ||
172 | return false; | ||
173 | |||
174 | content -= amount; | ||
175 | return true; | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | return false; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | /// <summary> | ||
184 | /// Add tokens to the bucket over time. The number of tokens added each | ||
185 | /// call depends on the length of time that has passed since the last | ||
186 | /// call to Drip | ||
187 | /// </summary> | ||
188 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> | ||
189 | public bool Drip() | ||
190 | { | ||
191 | if (tokensPerMS == 0) | ||
192 | { | ||
193 | content = maxBurst; | ||
194 | return true; | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | int now = Environment.TickCount & Int32.MaxValue; | ||
199 | int deltaMS = now - lastDrip; | ||
200 | |||
201 | if (deltaMS <= 0) | ||
202 | { | ||
203 | if (deltaMS < 0) | ||
204 | lastDrip = now; | ||
205 | return false; | ||
206 | } | ||
207 | |||
208 | int dripAmount = deltaMS * tokensPerMS; | ||
209 | |||
210 | content = Math.Min(content + dripAmount, maxBurst); | ||
211 | lastDrip = now; | ||
212 | |||
213 | return true; | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index f3242c1..e43f7cf 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | |||
@@ -37,97 +37,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
37 | /// </summary> | 37 | /// </summary> |
38 | public sealed class UnackedPacketCollection | 38 | public sealed class UnackedPacketCollection |
39 | { | 39 | { |
40 | /// <summary>Synchronization primitive. A lock must be acquired on this | ||
41 | /// object before calling any of the unsafe methods</summary> | ||
42 | public object SyncRoot = new object(); | ||
43 | |||
44 | /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary> | ||
45 | private SortedDictionary<uint, OutgoingPacket> packets = new SortedDictionary<uint, OutgoingPacket>(); | ||
46 | |||
47 | /// <summary>Gets the total number of unacked packets</summary> | ||
48 | public int Count { get { return packets.Count; } } | ||
49 | |||
50 | /// <summary> | 40 | /// <summary> |
51 | /// Default constructor | 41 | /// Holds information about a pending acknowledgement |
52 | /// </summary> | 42 | /// </summary> |
53 | public UnackedPacketCollection() | 43 | private struct PendingAck |
54 | { | 44 | { |
55 | } | 45 | /// <summary>Sequence number of the packet to remove</summary> |
46 | public uint SequenceNumber; | ||
47 | /// <summary>Environment.TickCount value when the remove was queued. | ||
48 | /// This is used to update round-trip times for packets</summary> | ||
49 | public int RemoveTime; | ||
50 | /// <summary>Whether or not this acknowledgement was attached to a | ||
51 | /// resent packet. If so, round-trip time will not be calculated</summary> | ||
52 | public bool FromResend; | ||
56 | 53 | ||
57 | /// <summary> | 54 | public PendingAck(uint sequenceNumber, int currentTime, bool fromResend) |
58 | /// Add an unacked packet to the collection | ||
59 | /// </summary> | ||
60 | /// <param name="packet">Packet that is awaiting acknowledgement</param> | ||
61 | /// <returns>True if the packet was successfully added, false if the | ||
62 | /// packet already existed in the collection</returns> | ||
63 | public bool Add(OutgoingPacket packet) | ||
64 | { | ||
65 | lock (SyncRoot) | ||
66 | { | 55 | { |
67 | if (!packets.ContainsKey(packet.SequenceNumber)) | 56 | SequenceNumber = sequenceNumber; |
68 | { | 57 | RemoveTime = currentTime; |
69 | packets.Add(packet.SequenceNumber, packet); | 58 | FromResend = fromResend; |
70 | return true; | ||
71 | } | ||
72 | return false; | ||
73 | } | 59 | } |
74 | } | 60 | } |
75 | 61 | ||
76 | /// <summary> | 62 | /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary> |
77 | /// Removes a packet from the collection without attempting to obtain a | 63 | private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>(); |
78 | /// lock first | 64 | /// <summary>Holds packets that need to be added to the unacknowledged list</summary> |
79 | /// </summary> | 65 | private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>(); |
80 | /// <param name="sequenceNumber">Sequence number of the packet to remove</param> | 66 | /// <summary>Holds information about pending acknowledgements</summary> |
81 | /// <returns>True if the packet was found and removed, otherwise false</returns> | 67 | private LocklessQueue<PendingAck> m_pendingRemoves = new LocklessQueue<PendingAck>(); |
82 | public bool RemoveUnsafe(uint sequenceNumber) | ||
83 | { | ||
84 | return packets.Remove(sequenceNumber); | ||
85 | } | ||
86 | |||
87 | /// <summary> | ||
88 | /// Removes a packet from the collection without attempting to obtain a | ||
89 | /// lock first | ||
90 | /// </summary> | ||
91 | /// <param name="sequenceNumber">Sequence number of the packet to remove</param> | ||
92 | /// <param name="packet">Returns the removed packet</param> | ||
93 | /// <returns>True if the packet was found and removed, otherwise false</returns> | ||
94 | public bool RemoveUnsafe(uint sequenceNumber, out OutgoingPacket packet) | ||
95 | { | ||
96 | if (packets.TryGetValue(sequenceNumber, out packet)) | ||
97 | { | ||
98 | packets.Remove(sequenceNumber); | ||
99 | return true; | ||
100 | } | ||
101 | |||
102 | return false; | ||
103 | } | ||
104 | 68 | ||
105 | /// <summary> | 69 | /// <summary> |
106 | /// Removes all elements from the collection | 70 | /// Add an unacked packet to the collection |
107 | /// </summary> | 71 | /// </summary> |
108 | public void Clear() | 72 | /// <param name="packet">Packet that is awaiting acknowledgement</param> |
73 | /// <returns>True if the packet was successfully added, false if the | ||
74 | /// packet already existed in the collection</returns> | ||
75 | /// <remarks>This does not immediately add the ACK to the collection, | ||
76 | /// it only queues it so it can be added in a thread-safe way later</remarks> | ||
77 | public void Add(OutgoingPacket packet) | ||
109 | { | 78 | { |
110 | lock (SyncRoot) | 79 | m_pendingAdds.Enqueue(packet); |
111 | packets.Clear(); | ||
112 | } | 80 | } |
113 | 81 | ||
114 | /// <summary> | 82 | /// <summary> |
115 | /// Gets the packet with the lowest sequence number | 83 | /// Marks a packet as acknowledged |
116 | /// </summary> | 84 | /// </summary> |
117 | /// <returns>The packet with the lowest sequence number, or null if the | 85 | /// <param name="sequenceNumber">Sequence number of the packet to |
118 | /// collection is empty</returns> | 86 | /// acknowledge</param> |
119 | public OutgoingPacket GetOldest() | 87 | /// <param name="currentTime">Current value of Environment.TickCount</param> |
88 | /// <remarks>This does not immediately acknowledge the packet, it only | ||
89 | /// queues the ack so it can be handled in a thread-safe way later</remarks> | ||
90 | public void Remove(uint sequenceNumber, int currentTime, bool fromResend) | ||
120 | { | 91 | { |
121 | lock (SyncRoot) | 92 | m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); |
122 | { | ||
123 | using (SortedDictionary<uint, OutgoingPacket>.ValueCollection.Enumerator e = packets.Values.GetEnumerator()) | ||
124 | { | ||
125 | if (e.MoveNext()) | ||
126 | return e.Current; | ||
127 | else | ||
128 | return null; | ||
129 | } | ||
130 | } | ||
131 | } | 93 | } |
132 | 94 | ||
133 | /// <summary> | 95 | /// <summary> |
@@ -138,15 +100,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
138 | /// packet is considered expired</param> | 100 | /// packet is considered expired</param> |
139 | /// <returns>A list of all expired packets according to the given | 101 | /// <returns>A list of all expired packets according to the given |
140 | /// expiration timeout</returns> | 102 | /// expiration timeout</returns> |
103 | /// <remarks>This function is not thread safe, and cannot be called | ||
104 | /// multiple times concurrently</remarks> | ||
141 | public List<OutgoingPacket> GetExpiredPackets(int timeoutMS) | 105 | public List<OutgoingPacket> GetExpiredPackets(int timeoutMS) |
142 | { | 106 | { |
107 | ProcessQueues(); | ||
108 | |||
143 | List<OutgoingPacket> expiredPackets = null; | 109 | List<OutgoingPacket> expiredPackets = null; |
144 | 110 | ||
145 | lock (SyncRoot) | 111 | if (m_packets.Count > 0) |
146 | { | 112 | { |
147 | int now = Environment.TickCount; | 113 | int now = Environment.TickCount & Int32.MaxValue; |
148 | foreach (OutgoingPacket packet in packets.Values) | 114 | |
115 | foreach (OutgoingPacket packet in m_packets.Values) | ||
149 | { | 116 | { |
117 | // TickCount of zero means a packet is in the resend queue | ||
118 | // but hasn't actually been sent over the wire yet | ||
150 | if (packet.TickCount == 0) | 119 | if (packet.TickCount == 0) |
151 | continue; | 120 | continue; |
152 | 121 | ||
@@ -154,16 +123,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
154 | { | 123 | { |
155 | if (expiredPackets == null) | 124 | if (expiredPackets == null) |
156 | expiredPackets = new List<OutgoingPacket>(); | 125 | expiredPackets = new List<OutgoingPacket>(); |
126 | |||
127 | // The TickCount will be set to the current time when the packet | ||
128 | // is actually sent out again | ||
129 | packet.TickCount = 0; | ||
130 | |||
157 | expiredPackets.Add(packet); | 131 | expiredPackets.Add(packet); |
158 | } | 132 | } |
159 | else | ||
160 | { | ||
161 | break; | ||
162 | } | ||
163 | } | 133 | } |
164 | } | 134 | } |
165 | 135 | ||
166 | return expiredPackets; | 136 | return expiredPackets; |
167 | } | 137 | } |
138 | |||
139 | private void ProcessQueues() | ||
140 | { | ||
141 | // Process all the pending adds | ||
142 | OutgoingPacket pendingAdd; | ||
143 | while (m_pendingAdds.Dequeue(out pendingAdd)) | ||
144 | m_packets[pendingAdd.SequenceNumber] = pendingAdd; | ||
145 | |||
146 | // Process all the pending removes, including updating statistics and round-trip times | ||
147 | PendingAck pendingRemove; | ||
148 | OutgoingPacket ackedPacket; | ||
149 | while (m_pendingRemoves.Dequeue(out pendingRemove)) | ||
150 | { | ||
151 | if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket)) | ||
152 | { | ||
153 | m_packets.Remove(pendingRemove.SequenceNumber); | ||
154 | |||
155 | // Update stats | ||
156 | System.Threading.Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); | ||
157 | |||
158 | if (!pendingRemove.FromResend) | ||
159 | { | ||
160 | // Calculate the round-trip time for this packet and its ACK | ||
161 | int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount; | ||
162 | if (rtt > 0) | ||
163 | ackedPacket.Client.UpdateRoundTrip(rtt); | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | } | 168 | } |
169 | } | 169 | } |