From 611327e1040fa706665c543f67f9331a7e0136c5 Mon Sep 17 00:00:00 2001 From: MW Date: Mon, 10 Dec 2007 13:27:23 +0000 Subject: [PATCH] more work on texture downloading. Refractored the TextureDownloadModule (but currently to make debugging easier, it is running as a non shared module, so this results in a instance of this module being created for each region (and a extra thread per region), this will be changed back soon. Removed the old texture handling/sending code from AssetCache. A few other small changes/fixes. --- .../Communications/Cache/AssetCache.cs | 303 +++--------------- .../Cache/AssetTransactionManager.cs | 4 +- .../Communications/Cache/AssetTransactions.cs | 127 ++++---- .../Communications/Capabilities/LLSD.cs | 2 +- OpenSim/Framework/IClientAPI.cs | 9 +- OpenSim/Region/ClientStack/ClientView.cs | 3 +- .../Modules/TextureDownloadModule.cs | 282 ++++++++++------ .../Environment/Scenes/IScenePresenceBody.cs | 3 - OpenSim/Region/Environment/Scenes/Scene.cs | 4 +- 9 files changed, 298 insertions(+), 439 deletions(-) diff --git a/OpenSim/Framework/Communications/Cache/AssetCache.cs b/OpenSim/Framework/Communications/Cache/AssetCache.cs index d5ac67b35e..c164f0c01c 100644 --- a/OpenSim/Framework/Communications/Cache/AssetCache.cs +++ b/OpenSim/Framework/Communications/Cache/AssetCache.cs @@ -36,8 +36,7 @@ using OpenSim.Framework.Console; namespace OpenSim.Framework.Communications.Cache { - public delegate void DownloadComplete(AssetCache.TextureSender sender); - + public delegate void AssetRequestCallback(LLUUID assetID, AssetBase asset); /// @@ -57,21 +56,11 @@ namespace OpenSim.Framework.Communications.Cache public Dictionary RequestedTextures = new Dictionary(); //Textures requested from the asset server - public Dictionary SendingTextures = new Dictionary(); - public Dictionary RequestLists = new Dictionary(); - private BlockingQueue m_queueTextures = new BlockingQueue(); - private Dictionary> m_avatarReceivedTextures = new Dictionary>(); - - private Dictionary> m_timesTextureSent = - new Dictionary>(); - - private IAssetServer m_assetServer; private Thread m_assetCacheThread; - private Thread m_textureSenderThread; private LogBase m_log; /// @@ -88,9 +77,7 @@ namespace OpenSim.Framework.Communications.Cache m_assetCacheThread.IsBackground = true; m_assetCacheThread.Start(); - m_textureSenderThread = new Thread(new ThreadStart(ProcessTextureSenders)); - m_textureSenderThread.IsBackground = true; - m_textureSenderThread.Start(); + m_log = log; } @@ -104,7 +91,6 @@ namespace OpenSim.Framework.Communications.Cache try { ProcessAssetQueue(); - ProcessTextureQueue(); Thread.Sleep(500); } catch (Exception e) @@ -188,7 +174,7 @@ namespace OpenSim.Framework.Communications.Cache if (asset.Type == 0) { - if(Textures.ContainsKey(asset.FullID)) + if (Textures.ContainsKey(asset.FullID)) { result = "Duplicate ignored."; } @@ -250,67 +236,7 @@ namespace OpenSim.Framework.Communications.Cache return asset; } - /// - /// - /// - private void ProcessTextureQueue() - { - if (TextureRequests.Count == 0) - { - //no requests waiting - return; - } - int num; - num = TextureRequests.Count; - AssetRequest req; - for (int i = 0; i < num; i++) - { - req = (AssetRequest) TextureRequests[i]; - if (!SendingTextures.ContainsKey(req.ImageInfo.FullID)) - { - //Console.WriteLine("new texture to send"); - TextureSender sender = new TextureSender(req); - //sender.OnComplete += this.TextureSent; - SendingTextures.Add(req.ImageInfo.FullID, sender); - m_queueTextures.Enqueue(sender); - } - } - - TextureRequests.Clear(); - } - - public void ProcessTextureSenders() - { - while (true) - { - TextureSender sender = m_queueTextures.Dequeue(); - - bool finished = sender.SendTexture(); - if (finished) - { - TextureSent(sender); - } - else - { - // Console.WriteLine("readding texture"); - m_queueTextures.Enqueue(sender); - } - } - } - - /// - /// Event handler, called by a TextureSender object to say that texture has been sent - /// - /// - public void TextureSent(TextureSender sender) - { - if (SendingTextures.ContainsKey(sender.request.ImageInfo.FullID)) - { - SendingTextures.Remove(sender.request.ImageInfo.FullID); - // this.m_avatarReceivedTextures[sender.request.RequestUser.AgentId].Add(sender.request.ImageInfo.FullID); - } - } public void AssetReceived(AssetBase asset, bool IsTexture) { @@ -354,7 +280,7 @@ namespace OpenSim.Framework.Communications.Cache if (assetInf.Data.LongLength > 600) { //over 600 bytes so split up file - req.NumPackets = 1 + (int) (assetInf.Data.Length - 600 + 999)/1000; + req.NumPackets = 1 + (int)(assetInf.Data.Length - 600 + 999) / 1000; } else { @@ -400,6 +326,20 @@ namespace OpenSim.Framework.Communications.Cache //} } + private int CalculateNumPackets(int length) + { + int numPackets = 1; + + if (length > 600) + { + //over 600 bytes so split up file + int restData = (length - 600); + int restPackets = ((restData + 999) / 1000); + numPackets = 1 + restPackets; + } + + return numPackets; + } #region Assets /// @@ -458,7 +398,7 @@ namespace OpenSim.Framework.Communications.Cache if (asset.Data.LongLength > 600) { //over 600 bytes so split up file - req.NumPackets = 1 + (int) (asset.Data.Length - 600 + 999)/1000; + req.NumPackets = 1 + (int)(asset.Data.Length - 600 + 999) / 1000; } else { @@ -473,6 +413,7 @@ namespace OpenSim.Framework.Communications.Cache /// 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 @@ -492,7 +433,7 @@ namespace OpenSim.Framework.Communications.Cache AssetRequest req; for (int i = 0; i < num; i++) { - req = (AssetRequest) AssetRequests[i]; + req = (AssetRequest)AssetRequests[i]; //Console.WriteLine("sending asset " + req.RequestAssetID); TransferInfoPacket Transfer = new TransferInfoPacket(); Transfer.TransferInfo.ChannelType = 2; @@ -502,7 +443,7 @@ namespace OpenSim.Framework.Communications.Cache { Transfer.TransferInfo.Params = new byte[20]; Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); - int assType = (int) req.AssetInf.Type; + int assType = (int)req.AssetInf.Type; Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4); } else if (req.AssetRequestSource == 3) @@ -512,9 +453,9 @@ namespace OpenSim.Framework.Communications.Cache //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.Size = (int)req.AssetInf.Data.Length; Transfer.TransferInfo.TransferID = req.TransferRequestID; - req.RequestUser.OutPacket(Transfer,ThrottleOutPacketType.Asset); + req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset); if (req.NumPackets == 1) { @@ -573,79 +514,6 @@ namespace OpenSim.Framework.Communications.Cache #endregion - #region Textures - - /// - /// - /// - /// - /// - public void AddTextureRequest(IClientAPI userInfo, LLUUID imageID, uint packetNumber, int discard) - { - // System.Console.WriteLine("texture request for " + imageID.ToStringHyphenated() + " packetnumber= " + packetNumber); - //check to see if texture is in local cache, if not request from asset server - if (!m_avatarReceivedTextures.ContainsKey(userInfo.AgentId)) - { - m_avatarReceivedTextures.Add(userInfo.AgentId, new List()); - } - /* if(this.m_avatarReceivedTextures[userInfo.AgentId].Contains(imageID)) - { - //Console.WriteLine(userInfo.AgentId +" is requesting a image( "+ imageID+" that has already been sent to them"); - return; - }*/ - - if (!Textures.ContainsKey(imageID)) - { - if (!RequestedTextures.ContainsKey(imageID)) - { - //not is cache so request from asset server - AssetRequest request = new AssetRequest(); - request.RequestUser = userInfo; - request.RequestAssetID = imageID; - request.IsTextureRequest = true; - request.DiscardLevel = discard; - RequestedTextures.Add(imageID, request); - m_assetServer.RequestAsset(imageID, true); - } - return; - } - - // System.Console.WriteLine("texture already in cache"); - TextureImage imag = Textures[imageID]; - AssetRequest req = new AssetRequest(); - req.RequestUser = userInfo; - req.RequestAssetID = imageID; - req.IsTextureRequest = true; - req.ImageInfo = imag; - req.DiscardLevel = discard; - - req.NumPackets = CalculateNumPackets(imag.Data.Length); - - if (packetNumber != 0) - { - req.PacketCounter = (int) packetNumber; - } - - TextureRequests.Add(req); - } - - private int CalculateNumPackets(int length) - { - int numPackets = 1; - - if (length > 600) - { - //over 600 bytes so split up file - int restData = (length - 600); - int restPackets = ((restData+999)/1000); - numPackets = 1 + restPackets; - } - - return numPackets; - } - - #endregion - public class AssetRequest { public IClientAPI RequestUser; @@ -702,123 +570,28 @@ namespace OpenSim.Framework.Communications.Cache } } - public class TextureSender + + public class AssetRequestsList { - public AssetRequest request; - private int counter = 0; + public LLUUID AssetID; + public List Requests = new List(); - public TextureSender(AssetRequest req) + public AssetRequestsList(LLUUID assetID) { - request = req; - } - - public bool SendTexture() - { - SendPacket(); - counter++; - - if ((request.PacketCounter >= request.NumPackets) || counter > 100 || (request.NumPackets == 1) || - (request.DiscardLevel == -1)) - { - return true; - } - return false; - } - - public void SendPacket() - { - AssetRequest req = request; - //Console.WriteLine("sending " + req.ImageInfo.FullID); - if (req.PacketCounter == 0) - { - //first time for this request so send imagedata packet - if (req.NumPackets == 1) - { - //Console.WriteLine("only one packet so send whole file"); - ImageDataPacket im = new ImageDataPacket(); - im.Header.Reliable = false; - im.ImageID.Packets = 1; - im.ImageID.ID = req.ImageInfo.FullID; - im.ImageID.Size = (uint) req.ImageInfo.Data.Length; - im.ImageData.Data = req.ImageInfo.Data; - im.ImageID.Codec = 2; - req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - req.PacketCounter++; - //req.ImageInfo.l= time; - //System.Console.WriteLine("sent texture: " + req.ImageInfo.FullID); - //Console.WriteLine("sending single packet for " + req.ImageInfo.FullID.ToStringHyphenated()); - } - else - { - //more than one packet so split file up - ImageDataPacket im = new ImageDataPacket(); - im.Header.Reliable = false; - im.ImageID.Packets = (ushort) (req.NumPackets); - im.ImageID.ID = req.ImageInfo.FullID; - im.ImageID.Size = (uint) req.ImageInfo.Data.Length; - im.ImageData.Data = new byte[600]; - Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600); - im.ImageID.Codec = 2; - req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - - req.PacketCounter++; - //req.ImageInfo.last_used = time; - //System.Console.WriteLine("sent first packet of texture: " + req.ImageInfo.FullID); - //Console.WriteLine("sending packet 1 for " + req.ImageInfo.FullID.ToStringHyphenated()); - } - } - else - { - //Console.WriteLine("sending packet " + req.PacketCounter + " for " + req.ImageInfo.FullID.ToStringHyphenated()); - //send imagepacket - //more than one packet so split file up - ImagePacketPacket im = new ImagePacketPacket(); - im.Header.Reliable = false; - im.ImageID.Packet = (ushort) (req.PacketCounter); - im.ImageID.ID = req.ImageInfo.FullID; - int size = req.ImageInfo.Data.Length - 600 - (1000*(req.PacketCounter - 1)); - if (size > 1000) size = 1000; - //Console.WriteLine("length= {0} counter= {1} size= {2}",req.ImageInfo.Data.Length, req.PacketCounter, size); - im.ImageData.Data = new byte[size]; - Array.Copy(req.ImageInfo.Data, 600 + (1000*(req.PacketCounter - 1)), im.ImageData.Data, 0, size); - req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - req.PacketCounter++; - //req.ImageInfo.last_used = time; - //System.Console.WriteLine("sent a packet of texture: "+req.ImageInfo.FullID); - } - } - - private void SaveAssetToFile(string filename, byte[] data) - { - FileStream fs = File.Create(filename); - BinaryWriter bw = new BinaryWriter(fs); - bw.Write(data); - bw.Close(); - fs.Close(); + AssetID = assetID; } } - } - public class AssetRequestsList - { - public LLUUID AssetID; - public List Requests = new List(); - - public AssetRequestsList(LLUUID assetID) + public class NewAssetRequest { - AssetID = assetID; - } - } + public LLUUID AssetID; + public AssetRequestCallback Callback; - public class NewAssetRequest - { - public LLUUID AssetID; - public AssetRequestCallback Callback; - - public NewAssetRequest(LLUUID assetID, AssetRequestCallback callback) - { - AssetID = assetID; - Callback = callback; + public NewAssetRequest(LLUUID assetID, AssetRequestCallback callback) + { + AssetID = assetID; + Callback = callback; + } } } } diff --git a/OpenSim/Framework/Communications/Cache/AssetTransactionManager.cs b/OpenSim/Framework/Communications/Cache/AssetTransactionManager.cs index 580c56a619..7de84fa754 100644 --- a/OpenSim/Framework/Communications/Cache/AssetTransactionManager.cs +++ b/OpenSim/Framework/Communications/Cache/AssetTransactionManager.cs @@ -83,7 +83,7 @@ namespace OpenSim.Framework.Communications.Cache } public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, - byte[] data, bool storeLocal) + byte[] data, bool storeLocal, bool tempFile) { // Console.WriteLine("asset upload of " + assetID); AgentAssetTransactions transactions = GetUserTransActions(remoteClient.AgentId); @@ -92,7 +92,7 @@ namespace OpenSim.Framework.Communications.Cache AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction); if (uploader != null) { - uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal); + uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile); } } } diff --git a/OpenSim/Framework/Communications/Cache/AssetTransactions.cs b/OpenSim/Framework/Communications/Cache/AssetTransactions.cs index f9723683d4..51b80e5fcb 100644 --- a/OpenSim/Framework/Communications/Cache/AssetTransactions.cs +++ b/OpenSim/Framework/Communications/Cache/AssetTransactions.cs @@ -113,66 +113,6 @@ namespace OpenSim.Framework.Communications.Cache } // Nested Types - public class AssetCapsUploader - { - // Fields - private BaseHttpServer httpListener; - private LLUUID inventoryItemID; - private string m_assetDescription = ""; - private string m_assetName = ""; - private LLUUID m_folderID; - private LLUUID newAssetID; - private bool m_dumpImageToFile; - private string uploaderPath = ""; - - // Events - public event UpLoadedAsset OnUpLoad; - - // Methods - public void Initialise(string assetName, string assetDescription, LLUUID assetID, LLUUID inventoryItem, - LLUUID folderID, string path, BaseHttpServer httpServer, bool dumpImageToFile) - { - m_assetName = assetName; - m_assetDescription = assetDescription; - m_folderID = folderID; - newAssetID = assetID; - inventoryItemID = inventoryItem; - uploaderPath = path; - httpListener = httpServer; - m_dumpImageToFile = dumpImageToFile; - } - - private void SaveImageToFile(string filename, byte[] data) - { - FileStream output = File.Create(filename); - BinaryWriter writer = new BinaryWriter(output); - writer.Write(data); - writer.Close(); - output.Close(); - } - - public string uploaderCaps(byte[] data, string path, string param) - { - LLUUID inventoryItemID = this.inventoryItemID; - string text = ""; - LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete(); - complete.new_asset = newAssetID.ToStringHyphenated(); - complete.new_inventory_item = inventoryItemID; - complete.state = "complete"; - text = LLSDHelpers.SerialiseLLSDReply(complete); - httpListener.RemoveStreamHandler("POST", uploaderPath); - if (m_dumpImageToFile) - { - SaveImageToFile(m_assetName + ".jp2", data); - } - if (OnUpLoad != null) - { - OnUpLoad(m_assetName, "description", newAssetID, inventoryItemID, LLUUID.Zero, data, "", ""); - } - return text; - } - } - public class AssetXferUploader { // Fields @@ -230,7 +170,7 @@ namespace OpenSim.Framework.Communications.Cache } public void Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, - bool storeLocal) + bool storeLocal, bool tempFile) { ourClient = remoteClient; Asset = new AssetBase(); @@ -240,6 +180,9 @@ namespace OpenSim.Framework.Communications.Cache Asset.Data = data; Asset.Name = "blank"; Asset.Description = "empty"; + Asset.Local = storeLocal; + Asset.Temporary = tempFile; + TransactionID = transaction; m_storeLocal = storeLocal; if (Asset.Data.Length > 2) @@ -368,6 +311,67 @@ namespace OpenSim.Framework.Communications.Cache } } + #region Nested Classes currently not in use (waiting for them to be enabled) + public class AssetCapsUploader + { + // Fields + private BaseHttpServer httpListener; + private LLUUID inventoryItemID; + private string m_assetDescription = ""; + private string m_assetName = ""; + private LLUUID m_folderID; + private LLUUID newAssetID; + private bool m_dumpImageToFile; + private string uploaderPath = ""; + + // Events + public event UpLoadedAsset OnUpLoad; + + // Methods + public void Initialise(string assetName, string assetDescription, LLUUID assetID, LLUUID inventoryItem, + LLUUID folderID, string path, BaseHttpServer httpServer, bool dumpImageToFile) + { + m_assetName = assetName; + m_assetDescription = assetDescription; + m_folderID = folderID; + newAssetID = assetID; + inventoryItemID = inventoryItem; + uploaderPath = path; + httpListener = httpServer; + m_dumpImageToFile = dumpImageToFile; + } + + private void SaveImageToFile(string filename, byte[] data) + { + FileStream output = File.Create(filename); + BinaryWriter writer = new BinaryWriter(output); + writer.Write(data); + writer.Close(); + output.Close(); + } + + public string uploaderCaps(byte[] data, string path, string param) + { + LLUUID inventoryItemID = this.inventoryItemID; + string text = ""; + LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete(); + complete.new_asset = newAssetID.ToStringHyphenated(); + complete.new_inventory_item = inventoryItemID; + complete.state = "complete"; + text = LLSDHelpers.SerialiseLLSDReply(complete); + httpListener.RemoveStreamHandler("POST", uploaderPath); + if (m_dumpImageToFile) + { + SaveImageToFile(m_assetName + ".jp2", data); + } + if (OnUpLoad != null) + { + OnUpLoad(m_assetName, "description", newAssetID, inventoryItemID, LLUUID.Zero, data, "", ""); + } + return text; + } + } + public class NoteCardCapsUpdate { // Fields @@ -420,5 +424,6 @@ namespace OpenSim.Framework.Communications.Cache return text; } } + #endregion } } diff --git a/OpenSim/Framework/Communications/Capabilities/LLSD.cs b/OpenSim/Framework/Communications/Capabilities/LLSD.cs index 60b5f756b4..4efeeb1ee3 100644 --- a/OpenSim/Framework/Communications/Capabilities/LLSD.cs +++ b/OpenSim/Framework/Communications/Capabilities/LLSD.cs @@ -10,7 +10,7 @@ using System.Text; namespace OpenSim.Region.Capabilities { /// - /// + /// Borrowed from (a older version of ) libsl for now, as their new llsd code doesn't work we our decoding code. /// public static class LLSD { diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 38410f473a..6898f91d68 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -157,6 +157,13 @@ namespace OpenSim.Framework protected LLUUID m_requestedAssetID; private sbyte m_discardLevel; private uint m_packetNumber; + private float m_priority; + + public float Priority + { + get { return m_priority; } + set { m_priority = value; } + } /// /// @@ -348,7 +355,7 @@ namespace OpenSim.Framework public delegate void RemoveTaskInventory(IClientAPI remoteClient, LLUUID itemID, uint localID); public delegate void UDPAssetUploadRequest( - IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, bool storeLocal); + IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, bool storeLocal, bool tempFile); public delegate void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data); diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs index 31f01fc37a..1a544b8a7a 100644 --- a/OpenSim/Region/ClientStack/ClientView.cs +++ b/OpenSim/Region/ClientStack/ClientView.cs @@ -2738,6 +2738,7 @@ namespace OpenSim.Region.ClientStack args.RequestedAssetID = imageRequest.RequestImage[i].Image; args.DiscardLevel = imageRequest.RequestImage[i].DiscardLevel; args.PacketNumber = imageRequest.RequestImage[i].Packet; + args.Priority = imageRequest.RequestImage[i].DownloadPriority; OnRequestTexture(this, args); } @@ -2761,7 +2762,7 @@ namespace OpenSim.Region.ClientStack LLUUID temp=libsecondlife.LLUUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); OnAssetUploadRequest(this, temp, request.AssetBlock.TransactionID, request.AssetBlock.Type, - request.AssetBlock.AssetData, request.AssetBlock.StoreLocal); + request.AssetBlock.AssetData, request.AssetBlock.StoreLocal, request.AssetBlock.Tempfile); } break; case PacketType.RequestXfer: diff --git a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs index 66cdec728d..702af192bf 100644 --- a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs +++ b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs @@ -46,11 +46,10 @@ namespace OpenSim.Region.Environment.Modules private Scene m_scene; private List m_scenes = new List(); - private Dictionary> ClientRequests = - new Dictionary>(); - private BlockingQueue QueueSenders = new BlockingQueue(); - private Dictionary> InProcess = new Dictionary>(); + + private Dictionary m_userTextureServices = new Dictionary(); + private Thread m_thread; public TextureDownloadModule() @@ -85,55 +84,36 @@ namespace OpenSim.Region.Environment.Modules public bool IsSharedModule { - get { return true; } + get { return false; } } public void NewClient(IClientAPI client) { - lock (ClientRequests) - { - if (!ClientRequests.ContainsKey(client.AgentId)) - { - ClientRequests.Add(client.AgentId, new Dictionary()); - InProcess.Add(client.AgentId, new List()); - } - } client.OnRequestTexture += TextureRequest; - } - public void TextureCallback(LLUUID textureID, AssetBase asset) + private bool TryGetUserTextureService(LLUUID userID, out UserTextureDownloadService textureService) { - lock (ClientRequests) + lock (m_userTextureServices) { - foreach (Dictionary reqList in ClientRequests.Values) + if (m_userTextureServices.TryGetValue(userID, out textureService)) { - if (reqList.ContainsKey(textureID)) - { - //check the texture isn't already in the process of being sent to the client. - if (!InProcess[reqList[textureID].RequestUser.AgentId].Contains(textureID)) - { - TextureSender sender = new TextureSender(reqList[textureID], asset); - QueueSenders.Enqueue(sender); - InProcess[reqList[textureID].RequestUser.AgentId].Add(textureID); - reqList.Remove(textureID); - } - } + return true; } + + textureService = new UserTextureDownloadService(m_scene, QueueSenders); + m_userTextureServices.Add(userID, textureService); + return true; } } public void TextureRequest(Object sender, TextureRequestArgs e) { IClientAPI client = (IClientAPI)sender; - if (!ClientRequests[client.AgentId].ContainsKey(e.RequestedAssetID)) + UserTextureDownloadService textureService; + if (TryGetUserTextureService(client.AgentId, out textureService)) { - lock (ClientRequests) - { - AssetRequest request = new AssetRequest(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber); - ClientRequests[client.AgentId].Add(e.RequestedAssetID, request); - } - m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback); + textureService.HandleTextureRequest(client, e); } } @@ -142,57 +122,150 @@ namespace OpenSim.Region.Environment.Modules while (true) { TextureSender sender = QueueSenders.Dequeue(); - bool finished = sender.SendTexture(); - if (finished) + if (sender.Cancel) { TextureSent(sender); } else { - QueueSenders.Enqueue(sender); + bool finished = sender.SendTexturePacket(); + if (finished) + { + TextureSent(sender); + } + else + { + QueueSenders.Enqueue(sender); + } } } } private void TextureSent(TextureSender sender) { - if (InProcess[sender.request.RequestUser.AgentId].Contains(sender.request.RequestAssetID)) + sender.Sending = false; + } + + public class UserTextureDownloadService + { + private Dictionary m_textureSenders = new Dictionary(); + + private BlockingQueue m_sharedSendersQueue; + + private Scene m_scene; + + public UserTextureDownloadService(Scene scene, BlockingQueue sharedQueue) { - InProcess[sender.request.RequestUser.AgentId].Remove(sender.request.RequestAssetID); + m_scene = scene; + m_sharedSendersQueue = sharedQueue; + } + + public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e) + { + //TODO: should be working out the data size/ number of packets to be sent for each discard level + if ((e.DiscardLevel >= 0) || (e.Priority != 0)) + { + lock (m_textureSenders) + { + if (!m_textureSenders.ContainsKey(e.RequestedAssetID)) + { + TextureSender requestHandler = new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber); + m_textureSenders.Add(e.RequestedAssetID, requestHandler); + m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback); + } + else + { + m_textureSenders[e.RequestedAssetID].UpdateRequest(e.DiscardLevel, e.PacketNumber); + m_textureSenders[e.RequestedAssetID].counter = 0; + if ((m_textureSenders[e.RequestedAssetID].ImageLoaded) && (m_textureSenders[e.RequestedAssetID].Sending ==false)) + { + m_textureSenders[e.RequestedAssetID].Sending = true; + m_sharedSendersQueue.Enqueue(m_textureSenders[e.RequestedAssetID]); + } + } + } + } + else + { + lock (m_textureSenders) + { + if (m_textureSenders.ContainsKey(e.RequestedAssetID)) + { + m_textureSenders[e.RequestedAssetID].Cancel = true; + } + } + } + } + + public void TextureCallback(LLUUID textureID, AssetBase asset) + { + lock (m_textureSenders) + { + if (m_textureSenders.ContainsKey(textureID)) + { + if (!m_textureSenders[textureID].ImageLoaded) + { + m_textureSenders[textureID].TextureReceived(asset); + m_textureSenders[textureID].Sending = true; + m_textureSenders[textureID].counter = 0; + m_sharedSendersQueue.Enqueue(m_textureSenders[textureID]); + } + } + else + { + // Got a texture with no sender object to handle it, this shouldn't happen + } + } } } public class TextureSender { - public AssetRequest request; - private int counter = 0; + public int counter = 0; private AssetBase m_asset; public long DataPointer = 0; public int NumPackets = 0; public int PacketCounter = 0; + public bool Cancel = false; + public bool ImageLoaded = false; - public TextureSender(AssetRequest req, AssetBase asset) + public bool Sending = false; + + public IClientAPI RequestUser; + public LLUUID RequestedAssetID; + public int RequestedDiscardLevel = -1; + public uint StartPacketNumber = 0; + + // private int m_sentDiscardLevel = -1; + + public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber) { - request = req; - m_asset = asset; - - if (asset.Data.LongLength > 600) - { - NumPackets = 2 + (int)(asset.Data.Length - 601) / 1000; - } - else - { - NumPackets = 1; - } - - PacketCounter = (int)req.PacketNumber; + RequestUser = client; + RequestedAssetID = textureID; + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; } - public bool SendTexture() + public void TextureReceived(AssetBase asset) + { + m_asset = asset; + NumPackets = CalculateNumPackets(asset.Data.Length); + PacketCounter = (int)StartPacketNumber; + ImageLoaded = true; + } + + public void UpdateRequest(int discardLevel, uint packetNumber) + { + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; + PacketCounter = (int)StartPacketNumber; + } + + public bool SendTexturePacket() { SendPacket(); counter++; - if ((PacketCounter >= NumPackets) || counter > 100 || (NumPackets == 1) || (request.DiscardLevel == -1)) + if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1)))) ) { return true; } @@ -201,65 +274,68 @@ namespace OpenSim.Region.Environment.Modules public void SendPacket() { - AssetRequest req = request; - if (PacketCounter == 0) + if (PacketCounter <= NumPackets) { - if (NumPackets == 1) + if (PacketCounter == 0) { - ImageDataPacket im = new ImageDataPacket(); - im.Header.Reliable = false; - im.ImageID.Packets = 1; - im.ImageID.ID = m_asset.FullID; - im.ImageID.Size = (uint)m_asset.Data.Length; - im.ImageData.Data = m_asset.Data; - im.ImageID.Codec = 2; - req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; + if (NumPackets == 0) + { + ImageDataPacket im = new ImageDataPacket(); + im.Header.Reliable = false; + im.ImageID.Packets = 0; + im.ImageID.ID = m_asset.FullID; + im.ImageID.Size = (uint)m_asset.Data.Length; + im.ImageData.Data = m_asset.Data; + im.ImageID.Codec = 2; + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } + else + { + ImageDataPacket im = new ImageDataPacket(); + im.Header.Reliable = false; + im.ImageID.Packets = (ushort)(NumPackets); + im.ImageID.ID = m_asset.FullID; + im.ImageID.Size = (uint)m_asset.Data.Length; + im.ImageData.Data = new byte[600]; + Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); + im.ImageID.Codec = 2; + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } } else { - ImageDataPacket im = new ImageDataPacket(); + ImagePacketPacket im = new ImagePacketPacket(); im.Header.Reliable = false; - im.ImageID.Packets = (ushort)(NumPackets); + im.ImageID.Packet = (ushort)(PacketCounter); im.ImageID.ID = m_asset.FullID; - im.ImageID.Size = (uint)m_asset.Data.Length; - im.ImageData.Data = new byte[600]; - Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); - im.ImageID.Codec = 2; - req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1)); + if (size > 1000) size = 1000; + im.ImageData.Data = new byte[size]; + Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size); + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); PacketCounter++; } } - else - { - ImagePacketPacket im = new ImagePacketPacket(); - im.Header.Reliable = false; - im.ImageID.Packet = (ushort)(PacketCounter); - im.ImageID.ID = m_asset.FullID; - int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1)); - if (size > 1000) size = 1000; - im.ImageData.Data = new byte[size]; - Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size); - req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; - } } - } - public class AssetRequest - { - public IClientAPI RequestUser; - public LLUUID RequestAssetID; - public int DiscardLevel = -1; - public uint PacketNumber = 0; - - public AssetRequest(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber) + private int CalculateNumPackets(int length) { - RequestUser = client; - RequestAssetID = textureID; - DiscardLevel = discardLevel; - PacketNumber = packetNumber; + int numPackets = 0; + + if (length > 600) + { + //over 600 bytes so split up file + int restData = (length - 600); + int restPackets = ((restData + 999) / 1000); + numPackets = restPackets; + } + + return numPackets; } } + + } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Scenes/IScenePresenceBody.cs b/OpenSim/Region/Environment/Scenes/IScenePresenceBody.cs index 0f3bca1d64..b9d1232feb 100644 --- a/OpenSim/Region/Environment/Scenes/IScenePresenceBody.cs +++ b/OpenSim/Region/Environment/Scenes/IScenePresenceBody.cs @@ -35,8 +35,5 @@ namespace OpenSim.Region.Environment.Scenes public interface IScenePresenceBody { void processMovement(IClientAPI remoteClient, uint flags, LLQuaternion bodyRotation); - void SetAppearance(byte[] texture, AgentSetAppearancePacket.VisualParamBlock[] visualParam); - void SendOurAppearance(IClientAPI OurClient); - void SendAppearanceToOtherAgent(ScenePresence avatarInfo); } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index c5cb55c0ed..e9d83a1f2f 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -1019,7 +1019,7 @@ namespace OpenSim.Region.Environment.Scenes ScenePresence avatar = null; AvatarAppearance appearance; - LoadAvatarAppearance(client, out appearance); + GetAvatarAppearance(client, out appearance); avatar = m_innerScene.CreateAndAddScenePresence(client, child, appearance); @@ -1031,7 +1031,7 @@ namespace OpenSim.Region.Environment.Scenes return avatar; } - protected void LoadAvatarAppearance(IClientAPI client, out AvatarAppearance appearance) + protected void GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance) { if (m_AvatarFactory == null || !m_AvatarFactory.TryGetAvatarAppearance(client.AgentId, out appearance))