From e978d00914a25c12cc03efd597125e2948526681 Mon Sep 17 00:00:00 2001 From: MW Date: Wed, 27 Feb 2008 21:11:01 +0000 Subject: [PATCH] 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. --- .../Communications/Cache/AssetCache.cs | 35 +-- OpenSim/Framework/IClientAPI.cs | 3 + OpenSim/Region/ClientStack/ClientView.cs | 147 +++++----- .../Modules/AssetDownloadModule.cs | 270 +++++++++++++++++- .../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 061b857d02..abb7ce168f 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 /// - private Dictionary RequestedAssets; + // private Dictionary RequestedAssets; /// /// Asset requests with data which are ready to be sent back to requesters. This includes textures. /// - private List AssetRequests; + // private List AssetRequests; /// @@ -84,7 +84,7 @@ namespace OpenSim.Framework.Communications.Cache private readonly IAssetServer m_assetServer; - private readonly Thread m_assetCacheThread; + // private readonly Thread m_assetCacheThread; /// /// 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(); Textures = new Dictionary(); - AssetRequests = new List(); + // AssetRequests = new List(); - RequestedAssets = new Dictionary(); + // RequestedAssets = new Dictionary(); RequestLists = new Dictionary(); } @@ -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); } /// /// Process the asset queue which holds data which is packeted up and sent /// directly back to the client. /// - public void RunAssetManager() + /* public void RunAssetManager() { while (true) { @@ -193,7 +193,7 @@ namespace OpenSim.Framework.Communications.Cache m_log.Error("[ASSET CACHE]: " + e.ToString()); } } - } + }*/ /// /// 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 } + /* /// /// Calculate the number of packets required to send the asset to the client. /// @@ -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 2635a239e9..511bbad59c 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 de3e29d584..55c5726325 100644 --- a/OpenSim/Region/ClientStack/ClientView.cs +++ b/OpenSim/Region/ClientStack/ClientView.cs @@ -51,10 +51,10 @@ namespace OpenSim.Region.ClientStack /// 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); } /// @@ -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 012f92044e..ca01cae305 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 RegisteredScenes = new Dictionary(); + /// + /// Assets requests (for each user) which are waiting for asset server data. This includes texture requests + /// + private Dictionary> RequestedAssets; + + /// + /// Asset requests with data which are ready to be sent back to requesters. This includes textures. + /// + private List AssetRequests; + + private Thread m_thread; public AssetDownloadModule() { + RequestedAssets = new Dictionary>(); + AssetRequests = new List(); } 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; + } + + /// + /// Make an asset request the result of which will be packeted up and sent directly back to the client. + /// + /// + /// + 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 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(); + 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 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()); + } + } + } + + /// + /// Process the asset queue which sends packets directly back to the client. + /// + 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); + } + } + /// + /// Calculate the number of packets required to send the asset to the client. + /// + /// + /// + 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 e8218001b3..30a41b7efb 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;