From fb096dfbd54cfbcfa60be872cee1680eb521dd14 Mon Sep 17 00:00:00 2001
From: MW
Date: Mon, 21 Jul 2008 15:13:34 +0000
Subject: added experimental packet tracker (LLPacketTracker.cs), which can be
 told to track a packet and if it hasn't been acked within a set time, trigger
 a IClientAPI event, that the application/scene can handle. Currently only
 terrain packet tracking is finished, Tracking for initial Prim packets (first
 full update for a prim) is being worked on. Future improvements would be to
 make it a more generic packet tracker with callback delegates instead of
 events. Add a test event handler (which would fire after a minute if a
 terrain packet hadn't been acked) to scene to handle the OnUnackedTerrain
 event, which currently just resends the terrain patch. The idea of this
 packet tracking is for the region level application to be able to know if the
 client stack gave up on sending a packet.

---
 .../Communications/CommunicationsManager.cs        |   3 -
 OpenSim/Framework/IClientAPI.cs                    |  11 +-
 .../Region/ClientStack/LindenUDP/LLClientView.cs   | 115 ++++++----
 .../ClientStack/LindenUDP/LLPacketTracker.cs       | 234 +++++++++++++++++++++
 .../Environment/Modules/World/NPC/NPCAvatar.cs     |   9 +-
 OpenSim/Region/Environment/Scenes/Scene.cs         |   9 +
 .../Region/Environment/Scenes/SceneObjectPart.cs   |   2 +-
 .../Region/Examples/SimpleModule/MyNpcCharacter.cs |   9 +-
 8 files changed, 342 insertions(+), 50 deletions(-)
 create mode 100644 OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs

diff --git a/OpenSim/Framework/Communications/CommunicationsManager.cs b/OpenSim/Framework/Communications/CommunicationsManager.cs
index a45e236..5be7334 100644
--- a/OpenSim/Framework/Communications/CommunicationsManager.cs
+++ b/OpenSim/Framework/Communications/CommunicationsManager.cs
@@ -125,9 +125,7 @@ namespace OpenSim.Framework.Communications
                     {
                         return invService;
                     }
-
                 }
-
                 return null;
             }
         }
@@ -139,7 +137,6 @@ namespace OpenSim.Framework.Communications
                 host = m_defaultInventoryHost;
             }
 
-
             lock (m_inventoryServices)
             {
                 foreach (IInventoryServices service in m_inventoryServices)
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index bb44eb9..a835598 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -299,6 +299,9 @@ namespace OpenSim.Framework
     public delegate void GetScriptRunning(IClientAPI remoteClient, LLUUID objectID, LLUUID itemID);
     public delegate void SetScriptRunning(IClientAPI remoteClient, LLUUID objectID, LLUUID itemID, bool running);
 
+
+    public delegate void TerrainUnacked(IClientAPI remoteClient, int patchX, int patchY);
+
     #endregion
 
     public interface IClientAPI
@@ -501,6 +504,8 @@ namespace OpenSim.Framework
         event SetScriptRunning OnSetScriptRunning;
         event UpdateVector OnAutoPilotGo;
 
+        event TerrainUnacked OnUnackedTerrain;
+
         // [Obsolete("IClientAPI.OutPacket SHOULD NOT EXIST outside of LLClientView please refactor appropriately.")]
         void OutPacket(Packet newPack, ThrottleOutPacketType packType);
         void SendWearables(AvatarWearable[] wearables, int serial);
@@ -521,6 +526,8 @@ namespace OpenSim.Framework
 
         void SendLayerData(float[] map);
         void SendLayerData(int px, int py, float[] map);
+        void SendLayerData(int px, int py, float[] map, bool track);
+
         void MoveAgentIntoRegion(RegionInfo regInfo, LLVector3 pos, LLVector3 look);
         void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint);
         AgentCircuitData RequestClientInfo();
@@ -554,13 +561,13 @@ namespace OpenSim.Framework
                                    LLVector3 pos, LLVector3 vel, LLVector3 acc, LLQuaternion rotation, LLVector3 rvel,
                                    uint flags,
                                    LLUUID objectID, LLUUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem,
-                                   byte clickAction, byte[] textureanim, bool attachment, uint AttachPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius);
+                                   byte clickAction, byte[] textureanim, bool attachment, uint AttachPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius, bool track);
 
 
         void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape,
                                           LLVector3 pos, LLVector3 vel, LLVector3 acc, LLQuaternion rotation, LLVector3 rvel,
                                           uint flags, LLUUID objectID, LLUUID ownerID, string text, byte[] color,
-                                   uint parentID, byte[] particleSystem, byte clickAction);
+                                   uint parentID, byte[] particleSystem, byte clickAction, bool track);
 
         void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position,
                                  LLQuaternion rotation, LLVector3 velocity, LLVector3 rotationalvelocity, byte state, LLUUID AssetId);
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 2c05097..c9fc83a 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -118,6 +118,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
         private Dictionary<string, LLUUID> m_defaultAnimations = new Dictionary<string, LLUUID>();
 
+        private LLPacketTracker m_packetTracker;
+
         /* protected variables */
 
         protected static Dictionary<PacketType, PacketMethod> PacketHandlers =
@@ -282,6 +284,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         private SetScriptRunning handlerSetScriptRunning = null;
         private UpdateVector handlerAutoPilotGo = null;
 
+        private TerrainUnacked handlerUnackedTerrain = null;
+
+        //**
+
         /* Properties */
 
         public LLUUID SecureSessionId
@@ -377,6 +383,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         public LLClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, LLPacketServer packServer,
                           AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP)
         {
+            m_packetTracker = new LLPacketTracker(this);
+
             m_moneyBalance = 1000;
 
             m_channelVersion = Helpers.StringToField(scene.GetSimulatorVersion());
@@ -410,6 +418,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
             RegisterLocalPacketHandlers();
 
+
             m_clientThread = new Thread(new ThreadStart(AuthUser));
             m_clientThread.Name = "ClientThread";
             m_clientThread.IsBackground = true;
@@ -654,6 +663,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
         # endregion
 
+        protected int m_terrainCheckerCount = 0;
         /// <summary>
         /// Event handler for check client timer
         /// checks to ensure that the client is still connected
@@ -685,7 +695,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                 m_probesWithNoIngressPackets = 0;
                 m_lastPacketsReceived = m_packetsReceived;
             }
+
             //SendPacketStats();
+            m_packetTracker.Process();
+
+            if (m_terrainCheckerCount >= 4)
+            {
+                m_packetTracker.TerrainPacketCheck();
+               // m_packetTracker.PrimPacketCheck();
+                m_terrainCheckerCount = -1;
+            }
+            m_terrainCheckerCount++;
         }
 
         # region Setup
@@ -934,6 +954,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         public event SetScriptRunning OnSetScriptRunning;
         public event UpdateVector OnAutoPilotGo;
 
+        public event TerrainUnacked OnUnackedTerrain;
+
         #region Scene/Avatar to Client
 
         /// <summary>
@@ -1083,29 +1105,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         public virtual void SendLayerData(float[] map)
         {
             ThreadPool.QueueUserWorkItem(new WaitCallback(DoSendLayerData), (object)map);
-            //try
-            //{
-            //    int[] patches = new int[4];
-
-            //    for (int y = 0; y < 16; y++)
-            //    {
-            //        for (int x = 0; x < 16; x += 4)
-            //        {
-            //            patches[0] = x + 0 + y * 16;
-            //            patches[1] = x + 1 + y * 16;
-            //            patches[2] = x + 2 + y * 16;
-            //            patches[3] = x + 3 + y * 16;
-
-            //            Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches);
-            //            OutPacket(layerpack, ThrottleOutPacketType.Land);
-            //        }
-            //    }
-            //}
-            //catch (Exception e)
-            //{
-            //    m_log.Warn("[client]: " +
-            //               "ClientView.API.cs: SendLayerData() - Failed with exception " + e.ToString());
-            //}
+           
         }
 
         /// <summary>
@@ -1166,6 +1166,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         /// <param name="map">heightmap</param>
         public void SendLayerData(int px, int py, float[] map)
         {
+            SendLayerData(px, py, map, true);
+        }
+
+        public void SendLayerData(int px, int py, float[] map, bool track)
+        {
             try
             {
                 int[] patches = new int[1];
@@ -1177,6 +1182,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
                 LayerDataPacket layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches);
                 layerpack.Header.Zerocoded = true;
+               
+                if (track)
+                {
+                    layerpack.Header.Sequence = NextSeqNum();
+                    m_packetTracker.TrackTerrainPacket(layerpack.Header.Sequence, px, py);
+                }
+
                 OutPacket(layerpack, ThrottleOutPacketType.Land);
             }
             catch (Exception e)
@@ -2297,14 +2309,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                                           ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape,
                                           LLVector3 pos, LLVector3 vel, LLVector3 acc, LLQuaternion rotation, LLVector3 rvel,
                                           uint flags, LLUUID objectID, LLUUID ownerID, string text, byte[] color,
-                                          uint parentID, byte[] particleSystem, byte clickAction)
+                                          uint parentID, byte[] particleSystem, byte clickAction, bool track)
         {
             byte[] textureanim = new byte[0];
 
             SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, vel,
                                   acc, rotation, rvel, flags,
                                   objectID, ownerID, text, color, parentID, particleSystem,
-                                  clickAction, textureanim, false, (uint)0, LLUUID.Zero, LLUUID.Zero, 0, 0, 0);
+                                  clickAction, textureanim, false, (uint)0, LLUUID.Zero, LLUUID.Zero, 0, 0, 0, track);
         }
 
         public void SendPrimitiveToClient(
@@ -2312,8 +2324,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             LLVector3 pos, LLVector3 velocity, LLVector3 acceleration, LLQuaternion rotation, LLVector3 rotational_velocity,
             uint flags,
             LLUUID objectID, LLUUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem,
-            byte clickAction, byte[] textureanim, bool attachment, uint AttachPoint, LLUUID AssetId, LLUUID SoundId, double SoundGain, byte SoundFlags, double SoundRadius)
+            byte clickAction, byte[] textureanim, bool attachment, uint AttachPoint, LLUUID AssetId, LLUUID SoundId, double SoundGain, byte SoundFlags, double SoundRadius, bool track)
         {
+
             if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0)
                 rotation = LLQuaternion.Identity;
 
@@ -2396,6 +2409,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                 outPacket.ObjectData[0].TextureAnim = textureanim;
             }
             outPacket.Header.Zerocoded = true;
+
+            if (track)
+            {
+                outPacket.Header.Sequence = NextSeqNum();
+                m_packetTracker.TrackPrimPacket(outPacket.Header.Sequence, objectID);
+            }
+
             OutPacket(outPacket, ThrottleOutPacketType.Task);
         }
 
@@ -3816,7 +3836,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
             if (!Pack.Header.Resent)
             {
-                Pack.Header.Sequence = NextSeqNum();
+                if (Pack.Header.Sequence == 0)
+                {
+                    Pack.Header.Sequence = NextSeqNum();
+                }
 
                 if (Pack.Header.Reliable) //DIRTY HACK
                 {
@@ -3878,13 +3901,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                     {
                         foreach (uint ackedPacketId in NewPack.Header.AckList)
                         {
-                            Packet ackedPacket;
-
-                            if (m_needAck.TryGetValue(ackedPacketId, out ackedPacket))
-                            {
-                                m_unAckedBytes -= ackedPacket.ToBytes().Length;
-                                m_needAck.Remove(ackedPacketId);
-                            }
+                            RemovePacketFromNeedAckList(ackedPacketId);
                         }
                     }
                 }
@@ -3899,12 +3916,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                         foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
                         {
                             uint ackedPackId = block.ID;
-                            Packet ackedPacket;
-                            if (m_needAck.TryGetValue(ackedPackId, out ackedPacket))
-                            {
-                                m_unAckedBytes -= ackedPacket.ToBytes().Length;
-                                m_needAck.Remove(ackedPackId);
-                            }
+                            RemovePacketFromNeedAckList(ackedPackId);
                         }
                     }
                 }
@@ -3926,6 +3938,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             }
         }
 
+        private void RemovePacketFromNeedAckList(uint ackedPackId)
+        {
+            Packet ackedPacket;
+            if (m_needAck.TryGetValue(ackedPackId, out ackedPacket))
+            {
+                m_unAckedBytes -= ackedPacket.ToBytes().Length;
+                m_needAck.Remove(ackedPackId);
+
+                m_packetTracker.PacketAck(ackedPackId);
+            }
+        }
+
         /// <summary>
         /// The dreaded OutPacket.   This should only be called from withink the ClientStack itself right now
         /// This is the entry point for simulator packets to go out to the client.
@@ -4037,6 +4061,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             SendAcks();
             ResendUnacked();
             SendPacketStats();
+           // TerrainPacketTrack();
         }
 
         /// <summary>
@@ -4053,6 +4078,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             }
         }
 
+
         /// <summary>
         /// Emties out the old packets in the packet duplication tracking table.
         /// </summary>
@@ -4092,6 +4118,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
         #endregion
 
+        public void TriggerTerrainUnackedEvent(int patchX, int patchY)
+        {
+            handlerUnackedTerrain = OnUnackedTerrain;
+            if (handlerUnackedTerrain != null)
+            {
+                handlerUnackedTerrain(this, patchX, patchY);
+            }
+        }
+
         // Previously ClientView.ProcessPackets
 
         public bool AddMoney(int debit)
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs
new file mode 100644
index 0000000..e775a67
--- /dev/null
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs
@@ -0,0 +1,234 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using libsecondlife;
+
+namespace OpenSim.Region.ClientStack.LindenUDP
+{
+
+    public class LLPacketTracker
+    {
+        public delegate void PacketAcked(uint sequenceNumber);
+        public event PacketAcked OnPacketAcked;
+
+        protected List<uint> m_beenAcked = new List<uint>();
+
+        protected TerrainPacketTracker[,] m_sentTerrainPackets = new TerrainPacketTracker[16, 16];
+        protected Dictionary<LLUUID, PrimPacketTracker> m_sendPrimPackets = new Dictionary<LLUUID, PrimPacketTracker>();
+
+        protected LLClientView m_parentClient;
+
+        public LLPacketTracker(LLClientView parent)
+        {
+            m_parentClient = parent;
+            OnPacketAcked += TerrainPacketAcked;
+            //OnPacketAcked += PrimPacketAcked;
+        }
+
+        public void PacketAck(uint sequenceNumber)
+        {
+            lock (m_beenAcked)
+            {
+                m_beenAcked.Add(sequenceNumber);
+            }
+        }
+
+        public void TrackTerrainPacket(uint sequenceNumber, int patchX, int patchY)
+        {
+            TerrainPacketTracker tracker = new TerrainPacketTracker();
+            tracker.X = patchX;
+            tracker.Y = patchY;
+            tracker.SeqNumber = sequenceNumber;
+            tracker.TimeSent = DateTime.Now;
+            lock (m_sentTerrainPackets)
+            {
+                m_sentTerrainPackets[patchX, patchY] = tracker;
+            }
+        }
+
+        public void TrackPrimPacket(uint sequenceNumber, LLUUID primID)
+        {
+            PrimPacketTracker tracker = new PrimPacketTracker();
+            tracker.PrimID = primID;
+            tracker.TimeSent = DateTime.Now;
+            tracker.SeqNumber = sequenceNumber;
+            lock (m_sendPrimPackets)
+            {
+                m_sendPrimPackets[primID] = tracker;
+            }
+        }
+
+        public void TerrainPacketCheck()
+        {
+            DateTime now = DateTime.Now;
+            List<TerrainPacketTracker> resendList = new List<TerrainPacketTracker>();
+            lock (m_sentTerrainPackets)
+            {
+                for (int y = 0; y < 16; y++)
+                {
+                    for (int x = 0; x < 16; x++)
+                    {
+                        if (m_sentTerrainPackets[x, y] != null)
+                        {
+                            TerrainPacketTracker tracker = m_sentTerrainPackets[x, y];
+                            if ((now - tracker.TimeSent) > TimeSpan.FromMinutes(1))
+                            {
+                                tracker.TimeSent = now;
+                                m_sentTerrainPackets[x, y] = null;
+                                resendList.Add(tracker);
+                            }
+                        }
+                    }
+                }
+            }
+
+            foreach (TerrainPacketTracker tracker in resendList)
+            {
+                m_parentClient.TriggerTerrainUnackedEvent(tracker.X, tracker.Y);
+            }
+        }
+
+        public void PrimPacketCheck()
+        {
+            DateTime now = DateTime.Now;
+            List<PrimPacketTracker> resendList = new List<PrimPacketTracker>();
+            List<PrimPacketTracker> ackedList = new List<PrimPacketTracker>();
+
+            lock (m_sendPrimPackets)
+            {
+                foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values)
+                {
+                    if (tracker.Acked)
+                    {
+                        ackedList.Add(tracker);
+                    }
+                    else if (((now - tracker.TimeSent) > TimeSpan.FromMinutes(1)) && (!tracker.Acked))
+                    {
+                        resendList.Add(tracker);
+                    }
+                }
+            }
+
+            foreach (PrimPacketTracker tracker in resendList)
+            {
+                lock (m_sendPrimPackets)
+                {
+                    m_sendPrimPackets.Remove(tracker.PrimID);
+                }
+                //call event
+                Console.WriteLine("Prim packet not acked, " + tracker.PrimID.ToString());
+            }
+            
+           
+            RemovePrimTrackers(ackedList);
+        }
+
+        public void PrimTrackerCleanup()
+        {
+            List<PrimPacketTracker> ackedList = new List<PrimPacketTracker>();
+
+            lock (m_sendPrimPackets)
+            {
+                foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values)
+                {
+                    if (tracker.Acked)
+                    {
+                        ackedList.Add(tracker);
+                    }
+                }
+            }
+            Thread.Sleep(15); //give a little bit of time for other code to access list before we lock it again
+
+            RemovePrimTrackers(ackedList);
+        }
+
+        protected void RemovePrimTrackers(List<PrimPacketTracker> ackedList)
+        {
+            lock (m_sendPrimPackets)
+            {
+                foreach (PrimPacketTracker tracker in ackedList)
+                {
+                    m_sendPrimPackets.Remove(tracker.PrimID);
+                }
+            }
+        }
+
+        protected void TerrainPacketAcked(uint sequence)
+        {
+            lock (m_sentTerrainPackets)
+            {
+                for (int y = 0; y < 16; y++)
+                {
+                    for (int x = 0; x < 16; x++)
+                    {
+                        if (m_sentTerrainPackets[x, y] != null)
+                        {
+                            if (m_sentTerrainPackets[x, y].SeqNumber == sequence)
+                            {
+                                m_sentTerrainPackets[x, y] = null;
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        protected void PrimPacketAcked(uint sequence)
+        {
+            lock (m_sendPrimPackets)
+            {
+                foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values)
+                {
+                    if (tracker.SeqNumber == sequence)
+                    {
+                        tracker.Acked = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        public void Process()
+        {
+            List<uint> ackedPackets = null;
+            lock (m_beenAcked)
+            {
+                ackedPackets = new List<uint>(m_beenAcked);
+                m_beenAcked.Clear();
+            }
+
+            if (ackedPackets != null)
+            {
+                foreach (uint packetId in ackedPackets)
+                {
+                    if (OnPacketAcked != null)
+                    {
+                        OnPacketAcked(packetId);
+                    }
+                }
+            }
+
+            // ackedPackets.Clear();
+            ackedPackets = null;
+        }
+
+        public class TerrainPacketTracker
+        {
+            public uint SeqNumber = 0;
+            public int X;
+            public int Y;
+            public DateTime TimeSent;
+
+        }
+
+        public class PrimPacketTracker
+        {
+            public uint SeqNumber = 0;
+            public DateTime TimeSent;
+            public LLUUID PrimID;
+            public bool Acked = false;
+        }
+    }
+}
diff --git a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs
index 040b9b7..574bc63 100644
--- a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs
@@ -296,6 +296,8 @@ namespace OpenSim.Region.Environment.Modules.World.NPC
         public event GetScriptRunning OnGetScriptRunning;
         public event SetScriptRunning OnSetScriptRunning;
         public event UpdateVector OnAutoPilotGo;
+
+        public event TerrainUnacked OnUnackedTerrain;
 #pragma warning restore 67
 
         #endregion
@@ -438,6 +440,9 @@ namespace OpenSim.Region.Environment.Modules.World.NPC
         public virtual void SendLayerData(int px, int py, float[] map)
         {
         }
+        public virtual void SendLayerData(int px, int py, float[] map, bool track)
+        {
+        }
 
         public virtual void MoveAgentIntoRegion(RegionInfo regInfo, LLVector3 pos, LLVector3 look)
         {
@@ -513,7 +518,7 @@ namespace OpenSim.Region.Environment.Modules.World.NPC
                                                   LLVector3 acc, LLQuaternion rotation, LLVector3 rvel, uint flags,
                                                   LLUUID objectID, LLUUID ownerID, string text, byte[] color,
                                                   uint parentID,
-                                                  byte[] particleSystem, byte clickAction)
+                                                  byte[] particleSystem, byte clickAction, bool track)
         {
         }
         public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID,
@@ -522,7 +527,7 @@ namespace OpenSim.Region.Environment.Modules.World.NPC
                                                   LLUUID objectID, LLUUID ownerID, string text, byte[] color,
                                                   uint parentID,
                                                   byte[] particleSystem, byte clickAction, byte[] textureanimation,
-                                                  bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius)
+                                                  bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius, bool track)
         {
         }
         public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID,
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs
index f602e9f..c2398b6 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.cs
@@ -2084,6 +2084,8 @@ namespace OpenSim.Region.Environment.Scenes
             client.OnGetScriptRunning += GetScriptRunning;
             client.OnSetScriptRunning += SetScriptRunning;
 
+            client.OnUnackedTerrain += TerrainUnAcked;
+
             // EventManager.TriggerOnNewClient(client);
         }
 
@@ -3703,5 +3705,12 @@ namespace OpenSim.Region.Environment.Scenes
 //                client.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Play, 0);
 //            });
         }
+
+
+        public void TerrainUnAcked(IClientAPI client, int patchX, int patchY)
+        {
+            //Console.WriteLine("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
+             client.SendLayerData(patchX, patchY, Heightmap.GetFloatsSerialised());
+        }
     }
 }              
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs
index 156310b..253a83e 100644
--- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs
@@ -2085,7 +2085,7 @@ namespace OpenSim.Region.Environment.Scenes
             remoteClient.SendPrimitiveToClient(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape,
                                                lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID,
                                                m_text, color, _parentID, m_particleSystem, m_clickAction, m_TextureAnimation, m_IsAttachment,
-                                               m_attachmentPoint,fromAssetID, Sound, SoundGain, SoundFlags, SoundRadius);
+                                               m_attachmentPoint,fromAssetID, Sound, SoundGain, SoundFlags, SoundRadius, false);
         }
 
         /// <summary>
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
index 6179ccf..c975df5 100644
--- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
@@ -202,6 +202,8 @@ namespace OpenSim.Region.Examples.SimpleModule
         public event SetScriptRunning OnSetScriptRunning;
         public event UpdateVector OnAutoPilotGo;
 
+       public event TerrainUnacked OnUnackedTerrain;
+
 #pragma warning restore 67
 
         private LLUUID myID = LLUUID.Random();
@@ -352,6 +354,9 @@ namespace OpenSim.Region.Examples.SimpleModule
         public virtual void SendLayerData(int px, int py, float[] map)
         {
         }
+        public virtual void SendLayerData(int px, int py, float[] map, bool track)
+        {
+        }
 
         public virtual void MoveAgentIntoRegion(RegionInfo regInfo, LLVector3 pos, LLVector3 look)
         {
@@ -427,7 +432,7 @@ namespace OpenSim.Region.Examples.SimpleModule
                                                   LLVector3 acc, LLQuaternion rotation, LLVector3 rvel, uint flags,
                                                   LLUUID objectID, LLUUID ownerID, string text, byte[] color,
                                                   uint parentID,
-                                                  byte[] particleSystem, byte clickAction)
+                                                  byte[] particleSystem, byte clickAction, bool track)
         {
         }
         public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID,
@@ -436,7 +441,7 @@ namespace OpenSim.Region.Examples.SimpleModule
                                                   LLUUID objectID, LLUUID ownerID, string text, byte[] color,
                                                   uint parentID,
                                                   byte[] particleSystem, byte clickAction, byte[] textureanimation,
-                                                  bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius)
+                                                  bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius, bool track)
         {
         }
         public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID,
-- 
cgit v1.1