From e978d00914a25c12cc03efd597125e2948526681 Mon Sep 17 00:00:00 2001
From: MW
Date: Wed, 27 Feb 2008 21:11:01 +0000
Subject: After seeing sdague do his happy dance over trunk working "the best
 he has ever seen". I'm not sure I should be doing this commit, but oh well.
 So anyway, it moves the Asset downloading (packet sending) to a module
 (AssetDownloadModule). So now at last, AssetCache should be just dealing with
 fetching assets from the asset server and caching them.

---
 .../Framework/Communications/Cache/AssetCache.cs   |  35 +--
 OpenSim/Framework/IClientAPI.cs                    |   3 +
 OpenSim/Region/ClientStack/ClientView.cs           | 147 +++++------
 .../Environment/Modules/AssetDownloadModule.cs     | 270 ++++++++++++++++++++-
 .../Region/Examples/SimpleApp/MyNpcCharacter.cs    |   1 +
 5 files changed, 367 insertions(+), 89 deletions(-)

diff --git a/OpenSim/Framework/Communications/Cache/AssetCache.cs b/OpenSim/Framework/Communications/Cache/AssetCache.cs
index 061b857..abb7ce1 100644
--- a/OpenSim/Framework/Communications/Cache/AssetCache.cs
+++ b/OpenSim/Framework/Communications/Cache/AssetCache.cs
@@ -69,12 +69,12 @@ namespace OpenSim.Framework.Communications.Cache
         ///
         /// Assets requests which are waiting for asset server data.  This includes texture requests
         /// </summary>
-           private Dictionary<LLUUID, AssetRequest> RequestedAssets;
+        //   private Dictionary<LLUUID, AssetRequest> RequestedAssets;
 
         /// <summary>
         /// Asset requests with data which are ready to be sent back to requesters.  This includes textures.
         /// </summary>
-         private List<AssetRequest> AssetRequests;
+       //  private List<AssetRequest> AssetRequests;
 
 
         /// <summary>
@@ -84,7 +84,7 @@ namespace OpenSim.Framework.Communications.Cache
 
         private readonly IAssetServer m_assetServer;
 
-        private readonly Thread m_assetCacheThread;
+      //  private readonly Thread m_assetCacheThread;
 
         /// <summary>
         /// Report statistical data.
@@ -94,8 +94,8 @@ namespace OpenSim.Framework.Communications.Cache
             m_log.InfoFormat("Assets:{0}  Textures:{1}  AssetRequests:{2}  RequestedAssets:{3}  RequestLists:{4}",
                 Assets.Count,
                 Textures.Count,
-                 AssetRequests.Count,
-                  RequestedAssets.Count,
+               //  AssetRequests.Count,
+              //    RequestedAssets.Count,
                 RequestLists.Count);
 
             int temporaryImages = 0;
@@ -150,9 +150,9 @@ namespace OpenSim.Framework.Communications.Cache
         {
             Assets = new Dictionary<LLUUID, AssetInfo>();
             Textures = new Dictionary<LLUUID, TextureImage>();
-             AssetRequests = new List<AssetRequest>();
+           //  AssetRequests = new List<AssetRequest>();
 
-             RequestedAssets = new Dictionary<LLUUID, AssetRequest>();
+           //  RequestedAssets = new Dictionary<LLUUID, AssetRequest>();
             RequestLists = new Dictionary<LLUUID, AssetRequestsList>();
         }
 
@@ -168,18 +168,18 @@ namespace OpenSim.Framework.Communications.Cache
             m_assetServer = assetServer;
             m_assetServer.SetReceiver(this);
 
-              m_assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
-              m_assetCacheThread.Name = "AssetCacheThread";
-               m_assetCacheThread.IsBackground = true;
-               m_assetCacheThread.Start();
-              OpenSim.Framework.ThreadTracker.Add(m_assetCacheThread);
+             // m_assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
+            //  m_assetCacheThread.Name = "AssetCacheThread";
+             //  m_assetCacheThread.IsBackground = true;
+             //  m_assetCacheThread.Start();
+             // OpenSim.Framework.ThreadTracker.Add(m_assetCacheThread);
         }
 
         /// <summary>
         /// Process the asset queue which holds data which is packeted up and sent
         /// directly back to the client.
         /// </summary>
-            public void RunAssetManager()
+         /*   public void RunAssetManager()
             {
                 while (true)
                 {
@@ -193,7 +193,7 @@ namespace OpenSim.Framework.Communications.Cache
                         m_log.Error("[ASSET CACHE]: " + e.ToString());
                     }
                 }
-            }
+            }*/
 
         /// <summary>
         /// Only get an asset if we already have it in the cache.
@@ -449,7 +449,7 @@ namespace OpenSim.Framework.Communications.Cache
                             StatsManager.SimExtraStats.AddAsset(assetInf);
                         }
 
-                          if (RequestedAssets.ContainsKey(assetInf.FullID))
+                        /*  if (RequestedAssets.ContainsKey(assetInf.FullID))
                            {
    #if DEBUG
                                //m_log.DebugFormat("[ASSET CACHE]: Moving {0} from RequestedAssets to AssetRequests", asset.FullID);
@@ -461,7 +461,7 @@ namespace OpenSim.Framework.Communications.Cache
 
                                RequestedAssets.Remove(assetInf.FullID);
                                AssetRequests.Add(req);
-                           }
+                           }*/
                     }
                 }
 
@@ -541,6 +541,7 @@ namespace OpenSim.Framework.Communications.Cache
 
         }
 
+        /*
           /// <summary>
            /// Calculate the number of packets required to send the asset to the client.
            /// </summary>
@@ -734,7 +735,7 @@ namespace OpenSim.Framework.Communications.Cache
                {
                }
            }
-
+        */
 
         public class AssetInfo : AssetBase
         {
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 2635a23..511bbad 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -390,6 +390,8 @@ namespace OpenSim.Framework
     public delegate void RemoveInventoryFolder(
         IClientAPI remoteClient, LLUUID folderID);
 
+    public delegate void RequestAsset(IClientAPI remoteClient, TransferRequestPacket transferRequest);
+
     public delegate void RezScript(IClientAPI remoteClient, LLUUID itemID, uint localID);
 
     public delegate void UpdateTaskInventory(IClientAPI remoteClient, LLUUID itemID, LLUUID folderID, uint localID);
@@ -503,6 +505,7 @@ namespace OpenSim.Framework
         event RezScript OnRezScript;
         event UpdateTaskInventory OnUpdateTaskInventory;
         event RemoveTaskInventory OnRemoveTaskItem;
+        event RequestAsset OnRequestAsset;
 
         event UUIDNameRequest OnNameFromUUIDRequest;
 
diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs
index de3e29d..55c5726 100644
--- a/OpenSim/Region/ClientStack/ClientView.cs
+++ b/OpenSim/Region/ClientStack/ClientView.cs
@@ -51,10 +51,10 @@ namespace OpenSim.Region.ClientStack
     /// </summary>
     public class ClientView : IClientAPI
     {
-//                ~ClientView()
-//                {
-//                    System.Console.WriteLine("[CLIENTVIEW]: Destructor called");                       
-//                }
+        //                ~ClientView()
+        //                {
+        //                    System.Console.WriteLine("[CLIENTVIEW]: Destructor called");                       
+        //                }
 
         private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
 
@@ -119,7 +119,7 @@ namespace OpenSim.Region.ClientStack
         protected LLVector3 m_startpos;
         protected EndPoint m_userEndPoint;
 
-        /* Instantiated Designated Event Delegates */ 
+        /* Instantiated Designated Event Delegates */
         //- used so we don't create new objects for each incoming packet and then toss it out later */
 
         private RequestAvatarProperties handler001 = null; //OnRequestAvatarProperties;
@@ -214,7 +214,8 @@ namespace OpenSim.Region.ClientStack
         private UpdateVector handler089 = null; //OnUpdatePrimGroupPosition;
         private UpdatePrimRotation handler090 = null; //OnUpdatePrimGroupRotation;
         private UpdatePrimGroupRotation handler091 = null; //OnUpdatePrimGroupMouseRotation;
-        private PacketStats handler093 = null; // OnPacketStats;
+        private PacketStats handler093 = null; // OnPacketStats;#
+        private RequestAsset handler094 = null; // OnRequestAsset;
 
 
         /* Properties */
@@ -363,7 +364,7 @@ namespace OpenSim.Region.ClientStack
             // We can't reach into other scenes and close the connection 
             // We need to do this over grid communications
             //m_scene.CloseAllAgents(CircuitCode);
-            
+
             // If we're not shutting down the circuit, then this is the last time we'll go here.
             // If we are shutting down the circuit, the UDP Server will come back here with 
             // ShutDownCircuit = false
@@ -502,7 +503,7 @@ namespace OpenSim.Region.ClientStack
         protected virtual void ClientLoop()
         {
             m_log.Info("[CLIENT]: Entered loop");
-            while( true )
+            while (true)
             {
                 QueItem nextPacket = m_packetQueue.Dequeue();
                 if (nextPacket.Incoming)
@@ -690,6 +691,7 @@ namespace OpenSim.Region.ClientStack
         public event RezScript OnRezScript;
         public event UpdateTaskInventory OnUpdateTaskInventory;
         public event RemoveTaskInventory OnRemoveTaskItem;
+        public event RequestAsset OnRequestAsset;
 
         public event UUIDNameRequest OnNameFromUUIDRequest;
 
@@ -1410,7 +1412,7 @@ namespace OpenSim.Region.ClientStack
             OutPacket(replyPacket, ThrottleOutPacketType.Task);
         }
 
-        public void SendAgentDataUpdate(LLUUID agentid, LLUUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname,string grouptitle)
+        public void SendAgentDataUpdate(LLUUID agentid, LLUUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
         {
             AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate);
             sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid;
@@ -1420,7 +1422,7 @@ namespace OpenSim.Region.ClientStack
             sendAgentDataUpdate.AgentData.GroupPowers = grouppowers;
             sendAgentDataUpdate.AgentData.GroupTitle = Helpers.StringToField(grouptitle);
             sendAgentDataUpdate.AgentData.LastName = Helpers.StringToField(lastname);
-            OutPacket(sendAgentDataUpdate,ThrottleOutPacketType.Task);
+            OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task);
         }
 
         /// <summary>
@@ -2329,10 +2331,10 @@ namespace OpenSim.Region.ClientStack
                     {
                         LLUUID partId = part.UUID;
 
-                        
-                        
-                        
-                        
+
+
+
+
                         UpdatePrimRotation handler090 = OnUpdatePrimGroupRotation;
                         UpdatePrimGroupRotation handler091 = OnUpdatePrimGroupMouseRotation;
 
@@ -2344,7 +2346,7 @@ namespace OpenSim.Region.ClientStack
                                 handler086 = OnUpdatePrimSinglePosition;
                                 if (handler086 != null)
                                 {
-                                    
+
                                     // System.Console.WriteLine("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
                                     handler086(localId, pos1, this);
                                 }
@@ -2355,18 +2357,18 @@ namespace OpenSim.Region.ClientStack
                                 handler087 = OnUpdatePrimSingleRotation;
                                 if (handler087 != null)
                                 {
-                                    
+
                                     //System.Console.WriteLine("new tab rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W);
                                     handler087(localId, rot1, this);
                                 }
                                 break;
                             case 3:
-                                
+
                                 LLQuaternion rot2 = new LLQuaternion(block.Data, 12, true);
                                 handler087 = OnUpdatePrimSingleRotation;
                                 if (handler087 != null)
                                 {
-                                    
+
                                     //System.Console.WriteLine("new mouse rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W);
                                     handler087(localId, rot2, this);
                                 }
@@ -2378,7 +2380,7 @@ namespace OpenSim.Region.ClientStack
                                 handler088 = OnUpdatePrimScale;
                                 if (handler088 != null)
                                 {
-                                    
+
                                     // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
                                     handler088(localId, scale1, this);
                                 }
@@ -2390,18 +2392,18 @@ namespace OpenSim.Region.ClientStack
 
                                 if (handler089 != null)
                                 {
-                                    
+
                                     handler089(localId, pos2, this);
                                 }
                                 break;
                             case 10:
-                                
+
                                 LLQuaternion rot3 = new LLQuaternion(block.Data, 0, true);
 
                                 handler090 = OnUpdatePrimGroupRotation;
                                 if (handler090 != null)
                                 {
-                                    
+
                                     //  Console.WriteLine("new rotation is " + rot.X + " , " + rot.Y + " , " + rot.Z + " , " + rot.W);
                                     handler090(localId, rot3, this);
                                 }
@@ -2429,7 +2431,7 @@ namespace OpenSim.Region.ClientStack
                                 handler088 = OnUpdatePrimScale;
                                 if (handler088 != null)
                                 {
-                                    
+
                                     //Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
                                     handler088(localId, scale2, this);
 
@@ -2449,10 +2451,10 @@ namespace OpenSim.Region.ClientStack
                                 handler088 = OnUpdatePrimScale;
                                 if (handler088 != null)
                                 {
-                                    
+
                                     // Console.WriteLine("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z );
                                     handler088(localId, scale5, this);
-                                    
+
                                     handler086 = OnUpdatePrimSinglePosition;
                                     if (handler086 != null)
                                     {
@@ -2762,7 +2764,7 @@ namespace OpenSim.Region.ClientStack
                     if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
                     {
                         //m_log.Debug("[NETWORK]: Resending " + packet.Type.ToString() + " packet, " +
-                                                            //(now - packet.TickCount) + "ms have passed");
+                        //(now - packet.TickCount) + "ms have passed");
 
                         packet.Header.Resent = true;
                         OutPacket(packet, ThrottleOutPacketType.Resend);
@@ -2863,13 +2865,13 @@ namespace OpenSim.Region.ClientStack
 
                     case PacketType.AvatarPropertiesRequest:
                         AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
-                        
+
                         handler001 = OnRequestAvatarProperties;
                         if (handler001 != null)
                         {
                             handler001(this, avatarProperties.AgentData.AvatarID);
                         }
-                        
+
 
                         break;
                     case PacketType.ChatFromViewer:
@@ -2900,7 +2902,7 @@ namespace OpenSim.Region.ClientStack
                                 handler002(this, args);
                         }
 
-                        
+
 
                         break;
                     case PacketType.ScriptDialogReply:
@@ -2921,7 +2923,7 @@ namespace OpenSim.Region.ClientStack
                             if (handler003 != null)
                                 handler003(this, args);
                         }
-                        
+
                         break;
                     case PacketType.ImprovedInstantMessage:
                         ImprovedInstantMessagePacket msgpack = (ImprovedInstantMessagePacket)Pack;
@@ -2940,7 +2942,7 @@ namespace OpenSim.Region.ClientStack
                                              msgpack.MessageBlock.BinaryBucket);
                         }
 
-                        
+
                         break;
 
                     case PacketType.AcceptFriendship:
@@ -2963,7 +2965,7 @@ namespace OpenSim.Region.ClientStack
                             handler005(this, agentID, transactionID, callingCardFolders);
                         }
 
-                        
+
 
 
                         break;
@@ -2977,7 +2979,7 @@ namespace OpenSim.Region.ClientStack
                         {
                             handler006(this, listOwnerAgentID, exFriendID);
                         }
-                        
+
 
                         break;
                     case PacketType.RezObject:
@@ -2995,7 +2997,7 @@ namespace OpenSim.Region.ClientStack
                             //rezPacket.RezData.RezSelected;
                             //rezPacket.RezData.FromTaskID;
                             //m_log.Info("[REZData]: " + rezPacket.ToString());
-                            
+
                             handler007(this, rezPacket.InventoryData.ItemID, rezPacket.RezData.RayEnd,
                                 rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID,
                                 rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection,
@@ -3004,7 +3006,7 @@ namespace OpenSim.Region.ClientStack
                                 rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem,
                                 rezPacket.RezData.FromTaskID);
                         }
-                        
+
                         break;
                     case PacketType.DeRezObject:
                         handler008 = OnDeRezObject;
@@ -3012,7 +3014,7 @@ namespace OpenSim.Region.ClientStack
                         {
                             handler008(Pack, this);
                         }
-                        
+
                         break;
                     case PacketType.ModifyLand:
                         ModifyLandPacket modify = (ModifyLandPacket)Pack;
@@ -3021,7 +3023,7 @@ namespace OpenSim.Region.ClientStack
                         {
                             if (OnModifyTerrain != null)
                             {
-                                
+
                                 for (int i = 0; i < modify.ParcelData.Length; i++)
                                 {
                                     handler009 = OnModifyTerrain;
@@ -3036,7 +3038,7 @@ namespace OpenSim.Region.ClientStack
                                 }
                             }
                         }
-                        
+
                         break;
                     case PacketType.RegionHandshakeReply:
 
@@ -3045,7 +3047,7 @@ namespace OpenSim.Region.ClientStack
                         {
                             handler010(this);
                         }
-                        
+
                         break;
                     case PacketType.AgentWearablesRequest:
                         handler011 = OnRequestWearables;
@@ -3054,7 +3056,7 @@ namespace OpenSim.Region.ClientStack
                         {
                             handler011();
                         }
-                        
+
 
                         handler012 = OnRequestAvatarsData;
 
@@ -3063,7 +3065,7 @@ namespace OpenSim.Region.ClientStack
                             handler012(this);
                         }
 
-                        
+
                         break;
                     case PacketType.AgentSetAppearance:
                         AgentSetAppearancePacket appear = (AgentSetAppearancePacket)Pack;
@@ -3073,7 +3075,7 @@ namespace OpenSim.Region.ClientStack
                         {
                             handler013(appear.ObjectData.TextureEntry, appear.VisualParam);
                         }
-                        
+
                         break;
                     case PacketType.AgentIsNowWearing:
                         if (OnAvatarNowWearing != null)
@@ -3094,7 +3096,7 @@ namespace OpenSim.Region.ClientStack
                                 handler014(this, wearingArgs);
                             }
 
-                            
+
                         }
                         break;
                     case PacketType.RezSingleAttachmentFromInv:
@@ -3102,28 +3104,28 @@ namespace OpenSim.Region.ClientStack
                         handler015 = OnRezSingleAttachmentFromInv;
                         if (handler015 != null)
                         {
-                            RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket) Pack;
-                            handler015(this, rez.ObjectData.ItemID, 
+                            RezSingleAttachmentFromInvPacket rez = (RezSingleAttachmentFromInvPacket)Pack;
+                            handler015(this, rez.ObjectData.ItemID,
                                         rez.ObjectData.AttachmentPt, rez.ObjectData.ItemFlags, rez.ObjectData.NextOwnerMask);
                         }
-                        
-                        break; 
+
+                        break;
                     case PacketType.ObjectAttach:
 
-                        
+
                         if (OnObjectAttach != null)
                         {
                             ObjectAttachPacket att = (ObjectAttachPacket)Pack;
-                            
+
                             handler016 = OnObjectAttach;
-                            
+
                             if (handler016 != null)
-                            {    
+                            {
                                 handler016(this, att.ObjectData[0].ObjectLocalID, att.AgentData.AttachmentPoint, att.ObjectData[0].Rotation);
                             }
                         }
-                        
-                        break; 
+
+                        break;
                     case PacketType.SetAlwaysRun:
                         SetAlwaysRunPacket run = (SetAlwaysRunPacket)Pack;
 
@@ -3131,7 +3133,7 @@ namespace OpenSim.Region.ClientStack
                         if (handler017 != null)
                             handler017(this, run.AgentData.AlwaysRun);
 
-                        
+
 
                         break;
                     case PacketType.CompleteAgentMovement:
@@ -3243,7 +3245,7 @@ namespace OpenSim.Region.ClientStack
 
                     case PacketType.SetStartLocationRequest:
                         SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack;
-                        
+
                         if (avSetStartLocationRequestPacket.AgentData.AgentID == AgentId && avSetStartLocationRequestPacket.AgentData.SessionID == SessionId)
                         {
                             handler027 = OnSetStartLocationRequest;
@@ -3494,7 +3496,7 @@ namespace OpenSim.Region.ClientStack
                                 byte set = permChanges.Set;
 
                                 handler043 = OnObjectPermissions;
-                                
+
                                 if (handler043 != null)
                                     OnObjectPermissions(this, AgentID, SessionID, field, localID, mask, set);
                             }
@@ -3539,7 +3541,7 @@ namespace OpenSim.Region.ClientStack
                     case PacketType.RequestImage:
                         RequestImagePacket imageRequest = (RequestImagePacket)Pack;
                         //Console.WriteLine("image request: " + Pack.ToString());
-                        
+
                         handler045 = null;
 
                         for (int i = 0; i < imageRequest.RequestImage.Length; i++)
@@ -3551,9 +3553,9 @@ namespace OpenSim.Region.ClientStack
                                 args.DiscardLevel = imageRequest.RequestImage[i].DiscardLevel;
                                 args.PacketNumber = imageRequest.RequestImage[i].Packet;
                                 args.Priority = imageRequest.RequestImage[i].DownloadPriority;
-                                
+
                                 handler045 = OnRequestTexture;
-                                
+
                                 if (handler045 != null)
                                     OnRequestTexture(this, args);
                             }
@@ -3562,7 +3564,12 @@ namespace OpenSim.Region.ClientStack
                     case PacketType.TransferRequest:
                         //Console.WriteLine("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
                         TransferRequestPacket transfer = (TransferRequestPacket)Pack;
-                        m_assetCache.AddAssetRequest(this, transfer);
+                        // m_assetCache.AddAssetRequest(this, transfer);
+                        handler094 = OnRequestAsset;
+                        if (handler094 != null)
+                        {
+                            handler094(this, transfer);
+                        }
                         break;
                     case PacketType.AssetUploadRequest:
                         AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack;
@@ -3606,7 +3613,7 @@ namespace OpenSim.Region.ClientStack
                         handler049 = OnConfirmXfer;
                         if (handler049 != null)
                         {
-                             handler049(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet);
+                            handler049(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet);
                         }
                         break;
                     case PacketType.CreateInventoryFolder:
@@ -3615,7 +3622,7 @@ namespace OpenSim.Region.ClientStack
                         handler050 = OnCreateNewInventoryFolder;
                         if (handler050 != null)
                         {
-                            
+
                             handler050(this, invFolder.FolderData.FolderID,
                                        (ushort)invFolder.FolderData.Type,
                                        Util.FieldToString(invFolder.FolderData.Name),
@@ -3709,7 +3716,7 @@ namespace OpenSim.Region.ClientStack
                         }
                         break;
                     case PacketType.PurgeInventoryDescendents:
-                        
+
                         PurgeInventoryDescendentsPacket Purge = (PurgeInventoryDescendentsPacket)Pack;
 
                         handler056 = OnPurgeInventoryDescendents;
@@ -4130,7 +4137,7 @@ namespace OpenSim.Region.ClientStack
                         }
                         break;
                     case PacketType.EstateCovenantRequest:
-                        
+
                         EstateCovenantRequestPacket.AgentDataBlock epack =
                             ((EstateCovenantRequestPacket)Pack).AgentData;
 
@@ -4246,9 +4253,9 @@ namespace OpenSim.Region.ClientStack
                         m_log.Warn("[CLIENT]: unhandled MuteListRequest packet");
                         break;
                     //case PacketType.AgentDataUpdateRequest:
-                        // TODO: handle this packet
-                        //m_log.Warn("[CLIENT]: unhandled AgentDataUpdateRequest packet");
-                        //break;
+                    // TODO: handle this packet
+                    //m_log.Warn("[CLIENT]: unhandled AgentDataUpdateRequest packet");
+                    //break;
 
                     case PacketType.ParcelDwellRequest:
                         // TODO: handle this packet
@@ -4275,9 +4282,9 @@ namespace OpenSim.Region.ClientStack
                         m_log.Warn("[CLIENT]: unhandled SoundTrigger packet");
                         break;
                     //case PacketType.UserInfoRequest:
-                        // TODO: handle this packet
-                        //m_log.Warn("[CLIENT]: unhandled UserInfoRequest packet");
-                        //break;
+                    // TODO: handle this packet
+                    //m_log.Warn("[CLIENT]: unhandled UserInfoRequest packet");
+                    //break;
                     case PacketType.InventoryDescendents:
                         // TODO: handle this packet
                         m_log.Warn("[CLIENT]: unhandled InventoryDescent packet");
diff --git a/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs b/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs
index 012f920..ca01cae 100644
--- a/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs
+++ b/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs
@@ -26,25 +26,57 @@
 * 
 */
 
+using System;
+using System.Collections.Generic;
+using System.Threading;
 using Nini.Config;
 using OpenSim.Framework;
 using OpenSim.Region.Environment.Interfaces;
 using OpenSim.Region.Environment.Scenes;
+using libsecondlife;
+using libsecondlife.Packets;
 
 namespace OpenSim.Region.Environment.Modules
 {
     public class AssetDownloadModule : IRegionModule
     {
         private Scene m_scene;
+        private Dictionary<LLUUID, Scene> RegisteredScenes = new Dictionary<LLUUID, Scene>();
+        ///
+        /// Assets requests (for each user) which are waiting for asset server data.  This includes texture requests
+        /// </summary>
+        private Dictionary<LLUUID, Dictionary<LLUUID,AssetRequest>> RequestedAssets;
+
+        /// <summary>
+        /// Asset requests with data which are ready to be sent back to requesters.  This includes textures.
+        /// </summary>
+        private List<AssetRequest> AssetRequests;
+
+        private Thread m_thread;
 
         public AssetDownloadModule()
         {
+            RequestedAssets = new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
+            AssetRequests = new List<AssetRequest>();
         }
 
         public void Initialise(Scene scene, IConfigSource config)
         {
-            m_scene = scene;
-            m_scene.EventManager.OnNewClient += NewClient;
+            if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
+            {
+                RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
+                scene.EventManager.OnNewClient += NewClient;
+            }
+
+            if (m_scene == null)
+            {
+                m_scene = scene;
+                m_thread = new Thread(new ThreadStart(RunAssetQueue));
+                m_thread.Name = "AssetDownloadQueueThread";
+                m_thread.IsBackground = true;
+                m_thread.Start();
+                OpenSim.Framework.ThreadTracker.Add(m_thread);
+            }
         }
 
         public void PostInitialise()
@@ -67,6 +99,240 @@ namespace OpenSim.Region.Environment.Modules
 
         public void NewClient(IClientAPI client)
         {
+            client.OnRequestAsset += AddAssetRequest;
+        }
+
+        /// <summary>
+        /// Make an asset request the result of which will be packeted up and sent directly back to the client.
+        /// </summary>
+        /// <param name="userInfo"></param>
+        /// <param name="transferRequest"></param>
+        public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest)
+        {
+            LLUUID requestID = null;
+            byte source = 2;
+            if (transferRequest.TransferInfo.SourceType == 2)
+            {
+                //direct asset request
+                requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
+            }
+            else if (transferRequest.TransferInfo.SourceType == 3)
+            {
+                //inventory asset request
+                requestID = new LLUUID(transferRequest.TransferInfo.Params, 80);
+                source = 3;
+                //Console.WriteLine("asset request " + requestID);
+            }
+
+            //not found asset
+            // so request from asset server
+            Dictionary<LLUUID, AssetRequest> userRequests = null;
+            if (RequestedAssets.TryGetValue(userInfo.AgentId, out userRequests))
+            {
+                if (!userRequests.ContainsKey(requestID))
+                {
+                   
+                    AssetRequest request = new AssetRequest();
+                    request.RequestUser = userInfo;
+                    request.RequestAssetID = requestID;
+                    request.TransferRequestID = transferRequest.TransferInfo.TransferID;
+                    request.AssetRequestSource = source;
+                    request.Params = transferRequest.TransferInfo.Params;
+                    userRequests[requestID] = request;
+                    m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
+                }
+            }
+            else
+            {
+                userRequests = new Dictionary<LLUUID, AssetRequest>();
+                AssetRequest request = new AssetRequest();
+                request.RequestUser = userInfo;
+                request.RequestAssetID = requestID;
+                request.TransferRequestID = transferRequest.TransferInfo.TransferID;
+                request.AssetRequestSource = source;
+                request.Params = transferRequest.TransferInfo.Params;
+                userRequests.Add(requestID, request);
+                RequestedAssets[userInfo.AgentId] = userRequests;
+                m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
+              
+            }
+            return;
+        }
+
+        public void AssetCallback(LLUUID assetID, AssetBase asset)
+        {
+            if (asset != null)
+            {
+                foreach (Dictionary<LLUUID, AssetRequest> userRequests in RequestedAssets.Values)
+                {
+                    if (userRequests.ContainsKey(assetID))
+                    {
+                        AssetRequest req = userRequests[assetID];
+                        if (req != null)
+                        {
+                            req.AssetInf = asset;
+                            req.NumPackets = CalculateNumPackets(asset.Data);
+
+                            userRequests.Remove(assetID);
+                            AssetRequests.Add(req);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void RunAssetQueue()
+        {
+            while (true)
+            {
+                try
+                {
+                    ProcessAssetQueue();
+                    Thread.Sleep(500);
+                }
+                catch (Exception e)
+                {
+                  //  m_log.Error("[ASSET CACHE]: " + e.ToString());
+                }
+            }
+        }
+
+        /// <summary>
+        /// Process the asset queue which sends packets directly back to the client.
+        /// </summary>
+        private void ProcessAssetQueue()
+        {
+            //should move the asset downloading to a module, like has been done with texture downloading
+            if (AssetRequests.Count == 0)
+            {
+                //no requests waiting
+                return;
+            }
+            // if less than 5, do all of them
+            int num = Math.Min(5, AssetRequests.Count);
+
+            AssetRequest req;
+            for (int i = 0; i < num; i++)
+            {
+                req = (AssetRequest)AssetRequests[i];
+                //Console.WriteLine("sending asset " + req.RequestAssetID);
+                TransferInfoPacket Transfer = new TransferInfoPacket();
+                Transfer.TransferInfo.ChannelType = 2;
+                Transfer.TransferInfo.Status = 0;
+                Transfer.TransferInfo.TargetType = 0;
+                if (req.AssetRequestSource == 2)
+                {
+                    Transfer.TransferInfo.Params = new byte[20];
+                    Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
+                    int assType = (int)req.AssetInf.Type;
+                    Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4);
+                }
+                else if (req.AssetRequestSource == 3)
+                {
+                    Transfer.TransferInfo.Params = req.Params;
+                    // Transfer.TransferInfo.Params = new byte[100];
+                    //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
+                    //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16);
+                }
+                Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
+                Transfer.TransferInfo.TransferID = req.TransferRequestID;
+                req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset);
+
+                if (req.NumPackets == 1)
+                {
+                    TransferPacketPacket TransferPacket = new TransferPacketPacket();
+                    TransferPacket.TransferData.Packet = 0;
+                    TransferPacket.TransferData.ChannelType = 2;
+                    TransferPacket.TransferData.TransferID = req.TransferRequestID;
+                    TransferPacket.TransferData.Data = req.AssetInf.Data;
+                    TransferPacket.TransferData.Status = 1;
+                    req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
+                }
+                else
+                {
+                    int processedLength = 0;
+                    // libsecondlife hardcodes 1500 as the maximum data chunk size
+                    int maxChunkSize = 1250;
+                    int packetNumber = 0;
+
+                    while (processedLength < req.AssetInf.Data.Length)
+                    {
+                        TransferPacketPacket TransferPacket = new TransferPacketPacket();
+                        TransferPacket.TransferData.Packet = packetNumber;
+                        TransferPacket.TransferData.ChannelType = 2;
+                        TransferPacket.TransferData.TransferID = req.TransferRequestID;
+
+                        int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize);
+                        byte[] chunk = new byte[chunkSize];
+                        Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length);
+
+                        TransferPacket.TransferData.Data = chunk;
+
+                        // 0 indicates more packets to come, 1 indicates last packet
+                        if (req.AssetInf.Data.Length - processedLength > maxChunkSize)
+                        {
+                            TransferPacket.TransferData.Status = 0;
+                        }
+                        else
+                        {
+                            TransferPacket.TransferData.Status = 1;
+                        }
+
+                        req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
+
+                        processedLength += chunkSize;
+                        packetNumber++;
+                    }
+                }
+            }
+
+            //remove requests that have been completed
+            for (int i = 0; i < num; i++)
+            {
+                AssetRequests.RemoveAt(0);
+            }
+        }
+        /// <summary>
+        /// Calculate the number of packets required to send the asset to the client.
+        /// </summary>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        private int CalculateNumPackets(byte[] data)
+        {
+            const uint m_maxPacketSize = 600;
+            int numPackets = 1;
+
+            if (data.LongLength > m_maxPacketSize)
+            {
+                // over max number of bytes so split up file
+                long restData = data.LongLength - m_maxPacketSize;
+                int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize);
+                numPackets += restPackets;
+            }
+
+            return numPackets;
+        }
+
+        public class AssetRequest
+        {
+            public IClientAPI RequestUser;
+            public LLUUID RequestAssetID;
+            public AssetBase AssetInf;
+            public AssetBase ImageInfo;
+            public LLUUID TransferRequestID;
+            public long DataPointer = 0;
+            public int NumPackets = 0;
+            public int PacketCounter = 0;
+            public bool IsTextureRequest;
+            public byte AssetRequestSource = 2;
+            public byte[] Params = null;
+            //public bool AssetInCache;
+            //public int TimeRequested; 
+            public int DiscardLevel = -1;
+
+            public AssetRequest()
+            {
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs
index e821800..30a41b7 100644
--- a/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleApp/MyNpcCharacter.cs
@@ -131,6 +131,7 @@ namespace SimpleApp
         public event RezScript OnRezScript;
         public event UpdateTaskInventory OnUpdateTaskInventory;
         public event RemoveTaskInventory OnRemoveTaskItem;
+        public event RequestAsset OnRequestAsset;
 
         public event UUIDNameRequest OnNameFromUUIDRequest;
 
-- 
cgit v1.1