From 334738fca96498f31842f42db974bc46da35d94a Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 30 Apr 2009 11:58:23 +0000 Subject: Thank you, mpallari, for a patch that increses efficiency by combining avatar updates into a single packet. Applied with changes. Fixes Mantis #3136 --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 75 ++++++++++++++++++---- 1 file changed, 63 insertions(+), 12 deletions(-) (limited to 'OpenSim/Region/ClientStack') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 48612ab..ada5d10 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections; using System.Collections.Generic; using System.Net; using System.Reflection; @@ -68,6 +69,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_cachedTextureSerial; private Timer m_clientPingTimer; + private Timer m_terseUpdateTimer; + private Dictionary m_terseUpdates = new Dictionary(); + private ushort m_terseTimeDilationLast = 0; + private bool m_clientBlocked; private int m_probesWithNoIngressPackets; @@ -116,6 +121,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected string m_activeGroupName = String.Empty; protected ulong m_activeGroupPowers; protected Dictionary m_groupPowers = new Dictionary(); + protected int m_terseUpdateRate = 50; + protected int m_terseUpdatesPerPacket = 5; // LLClientView Only public delegate void BinaryGenericMessage(Object sender, string method, byte[][] args); @@ -521,7 +528,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Shut down timers m_clientPingTimer.Stop(); - + m_terseUpdateTimer.Stop(); // This is just to give the client a reasonable chance of // flushing out all it's packets. There should probably @@ -602,6 +609,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // Shut down timers m_clientPingTimer.Stop(); + m_terseUpdateTimer.Stop(); } public void Restart() @@ -612,6 +620,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_clientPingTimer = new Timer(5000); m_clientPingTimer.Elapsed += CheckClientConnectivity; m_clientPingTimer.Enabled = true; + + m_terseUpdateTimer = new Timer(m_terseUpdateRate); + m_terseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); + m_terseUpdateTimer.AutoReset = false; } public void Terminate() @@ -833,6 +845,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_clientPingTimer.Elapsed += CheckClientConnectivity; m_clientPingTimer.Enabled = true; + m_terseUpdateTimer = new Timer(m_terseUpdateRate); + m_terseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); + m_terseUpdateTimer.AutoReset = false; + m_scene.AddNewClient(this); RefreshGroupMembership(); @@ -2696,8 +2712,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Send a terse positional/rotation/velocity update about an avatar to the client. This avatar can be that of /// the client itself. /// - public void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, - Vector3 velocity, Quaternion rotation) + public virtual void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, + Vector3 velocity, Quaternion rotation, UUID agentid) { if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) rotation = Quaternion.Identity; @@ -2706,17 +2722,52 @@ namespace OpenSim.Region.ClientStack.LindenUDP ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateAvatarImprovedBlock(localID, position, velocity, rotation); - ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); - // TODO: don't create new blocks if recycling an old packet - terse.RegionData.RegionHandle = regionHandle; - terse.RegionData.TimeDilation = timeDilation; - terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; - terse.ObjectData[0] = terseBlock; + + bool sendpacketnow = false; + lock (m_terseUpdates) + { + // Only one update per avatar per packet. No need to send old ones so just overwrite them. + m_terseUpdates[localID] = terseBlock; + m_terseTimeDilationLast = timeDilation; - terse.Header.Reliable = false; - terse.Header.Zerocoded = true; + // If packet is full or own movement packet, send it. + if (agentid == m_agentId || m_terseUpdates.Count >= m_terseUpdatesPerPacket) + { + m_terseUpdateTimer.Stop(); + sendpacketnow = true; + } + else if (m_terseUpdates.Count == 1) + m_terseUpdateTimer.Start(); + } + // Call ProcessAvatarTerseUpdates outside the lock + if (sendpacketnow) + ProcessAvatarTerseUpdates(this, null); + } + + private void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) + { + Dictionary dataBlocks = null; + + lock (m_terseUpdates) + { + ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); + terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; + terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[dataBlocks.Count]; - OutPacket(terse, ThrottleOutPacketType.Task); + int i = 0; + foreach (KeyValuePair dbe in m_terseUpdates) + { + terse.ObjectData[i] = dbe.Value; + i++; + } + terse.RegionData.TimeDilation = m_terseTimeDilationLast; + + terse.Header.Reliable = false; + terse.Header.Zerocoded = true; + OutPacket(terse, ThrottleOutPacketType.Task); + + m_terseUpdates.Clear(); + } } public void SendCoarseLocationUpdate(List users, List CoarseLocations) -- cgit v1.1