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.
afrisby
MW 2007-12-10 13:27:23 +00:00
parent 081a66d570
commit 611327e104
9 changed files with 298 additions and 439 deletions

View File

@ -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);
/// <summary>
@ -57,21 +56,11 @@ namespace OpenSim.Framework.Communications.Cache
public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>();
//Textures requested from the asset server
public Dictionary<LLUUID, TextureSender> SendingTextures = new Dictionary<LLUUID, TextureSender>();
public Dictionary<LLUUID, AssetRequestsList> RequestLists = new Dictionary<LLUUID, AssetRequestsList>();
private BlockingQueue<TextureSender> m_queueTextures = new BlockingQueue<TextureSender>();
private Dictionary<LLUUID, List<LLUUID>> m_avatarReceivedTextures = new Dictionary<LLUUID, List<LLUUID>>();
private Dictionary<LLUUID, Dictionary<LLUUID, int>> m_timesTextureSent =
new Dictionary<LLUUID, Dictionary<LLUUID, int>>();
private IAssetServer m_assetServer;
private Thread m_assetCacheThread;
private Thread m_textureSenderThread;
private LogBase m_log;
/// <summary>
@ -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;
}
/// <summary>
///
/// </summary>
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);
}
}
}
/// <summary>
/// Event handler, called by a TextureSender object to say that texture has been sent
/// </summary>
/// <param name="sender"></param>
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
/// <summary>
@ -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
/// </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
@ -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
/// <summary>
///
/// </summary>
/// <param name="userInfo"></param>
/// <param name="imageID"></param>
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<LLUUID>());
}
/* 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<NewAssetRequest> Requests = new List<NewAssetRequest>();
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<NewAssetRequest> Requests = new List<NewAssetRequest>();
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;
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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
}
}

View File

@ -10,7 +10,7 @@ using System.Text;
namespace OpenSim.Region.Capabilities
{
/// <summary>
///
/// Borrowed from (a older version of ) libsl for now, as their new llsd code doesn't work we our decoding code.
/// </summary>
public static class LLSD
{

View File

@ -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; }
}
/// <summary>
///
@ -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);

View File

@ -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:

View File

@ -46,11 +46,10 @@ namespace OpenSim.Region.Environment.Modules
private Scene m_scene;
private List<Scene> m_scenes = new List<Scene>();
private Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>> ClientRequests =
new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
private BlockingQueue<TextureSender> QueueSenders = new BlockingQueue<TextureSender>();
private Dictionary<LLUUID, List<LLUUID>> InProcess = new Dictionary<LLUUID, List<LLUUID>>();
private Dictionary<LLUUID, UserTextureDownloadService> m_userTextureServices = new Dictionary<LLUUID, UserTextureDownloadService>();
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<LLUUID, AssetRequest>());
InProcess.Add(client.AgentId, new List<LLUUID>());
}
}
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<LLUUID, AssetRequest> 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<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>();
private BlockingQueue<TextureSender> m_sharedSendersQueue;
private Scene m_scene;
public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> 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;
}
}
}
}

View File

@ -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);
}
}

View File

@ -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))