diff --git a/libsecondlife-cs/AssetSystem/AppearanceManager.cs b/libsecondlife-cs/AssetSystem/AppearanceManager.cs index 8d459a8f..3c2be5c0 100644 --- a/libsecondlife-cs/AssetSystem/AppearanceManager.cs +++ b/libsecondlife-cs/AssetSystem/AppearanceManager.cs @@ -122,7 +122,7 @@ namespace libsecondlife.AssetSystem public void WearOutfit(InventoryFolder outfitFolder, int TimeOut, bool removeExistingAttachments) { // Refresh download of outfit folder - if (!outfitFolder.RequestDownloadContents(false, false, true, true).RequestComplete.WaitOne(TimeOut, false)) + if (!outfitFolder.RequestDownloadContents(false, false, true).RequestComplete.WaitOne(TimeOut, false)) { Console.WriteLine("An error occured while downloads the folder contents of : " + outfitFolder.Name); } diff --git a/libsecondlife-cs/InventorySystem/InventoryFolder.cs b/libsecondlife-cs/InventorySystem/InventoryFolder.cs index 57d2d6a5..b3a3de38 100644 --- a/libsecondlife-cs/InventorySystem/InventoryFolder.cs +++ b/libsecondlife-cs/InventorySystem/InventoryFolder.cs @@ -82,11 +82,18 @@ namespace libsecondlife.InventorySystem /// Indicate if item data should be downloaded too (true), or only folders(false) /// Indicate if item data should be downloaded too (true), or only folders(false) /// The Request object for this download + public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items) + { + return RequestDownloadContents(recurse, folders, items, 0); + } + + [Obsolete("Clearing is no longer an option when requesting a download, you should use another version of this method", false)] public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items, bool clear) { - return RequestDownloadContents(recurse, folders, items, clear, 0); + return RequestDownloadContents(recurse, folders, items, 0); } + /// /// Request a download of this folder's content information. Block until done, or timeout is reached /// @@ -96,20 +103,21 @@ namespace libsecondlife.InventorySystem /// Delete locale cache information for the this folder and it's children, before downloading /// Milliseconds to wait before timing out, or -1 to wait indefinately. /// The Request object for this download - public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items, bool clear, int timeout) + public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items, int timeout) { - if (clear) - { - iManager.FolderClearContents(this, folders, items); - } - DownloadRequest_Folder dr = new DownloadRequest_Folder(FolderID, recurse, true, items); - iManager.RequestFolder(dr); + iManager.FolderRequestAppend(dr); dr.RequestComplete.WaitOne(timeout, false); return dr; } + [Obsolete("Clearing is no longer an option when requesting a download, you should use another version of this method", false)] + public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items, bool clear, int timeout) + { + return RequestDownloadContents(recurse, folders, items, timeout); + } + /// /// Request that a sub-folder be created /// @@ -121,7 +129,7 @@ namespace libsecondlife.InventorySystem LLUUID requestedFolderUUID = iManager.FolderCreate(name, FolderID); // Refresh child folders, to find created folder. - if (RequestDownloadContents(false, true, false, false).RequestComplete.WaitOne(30000, false) == false) + if (RequestDownloadContents(false, true, false).RequestComplete.WaitOne(30000, false) == false) { // Should probably note the timeout somewhere... } diff --git a/libsecondlife-cs/InventorySystem/InventoryManager.cs b/libsecondlife-cs/InventorySystem/InventoryManager.cs index 8387744e..43d6e0fe 100644 --- a/libsecondlife-cs/InventorySystem/InventoryManager.cs +++ b/libsecondlife-cs/InventorySystem/InventoryManager.cs @@ -63,8 +63,11 @@ namespace libsecondlife.InventorySystem private Dictionary FoldersByUUID = new Dictionary(); // Setup a dictionary to track download progress - private Dictionary FolderDownloadStatus = new Dictionary(); - private Queue FolderRequestQueue = new Queue(); +// protected Dictionary FolderDownloadStatus = new Dictionary(); + protected List FolderRequests = new List(); + protected bool CurrentlyDownloadingAFolder = false; + protected DownloadRequest_Folder CurrentlyDownloadingRequest = null; + private Mutex CurrentlyDownloadingMutex = new Mutex(); protected Dictionary FolderByType = new Dictionary(); @@ -89,6 +92,7 @@ namespace libsecondlife.InventorySystem Object = 6, Notecard = 7, Category = 8, + Folder = 8, RootCategory = 0, LSL = 10, [Obsolete] @@ -120,6 +124,9 @@ namespace libsecondlife.InventorySystem public delegate void On_InventoryItemReceived(LLUUID fromAgentID, string fromAgentName, uint parentEstateID, LLUUID regionID, LLVector3 position, DateTime timestamp, InventoryItem item); public event On_InventoryItemReceived OnInventoryItemReceived; + public delegate void On_InventoryFolderReceived(LLUUID fromAgentID, string fromAgentName, uint parentEstateID, LLUUID regionID, LLVector3 position, DateTime timestamp, InventoryFolder folder); + public event On_InventoryFolderReceived OnInventoryFolderReceived; + /// /// Primary constructor /// @@ -172,14 +179,10 @@ namespace libsecondlife.InventorySystem private void ClearState() { FoldersByUUID.Clear(); - lock (FolderDownloadStatus) - { - FolderDownloadStatus.Clear(); - } - lock (FolderRequestQueue) + lock (FolderRequests) { - FolderRequestQueue.Clear(); + FolderRequests.Clear(); } if (slClient.Self.InventoryRootFolderUUID != null) @@ -291,7 +294,7 @@ namespace libsecondlife.InventorySystem } // Try updating the current level's child folders, then look again - if (ifRoot.RequestDownloadContents(false, true, false, false).RequestComplete.WaitOne(1000, false)) + if (ifRoot.RequestDownloadContents(false, true, false).RequestComplete.WaitOne(1000, false)) { foreach (InventoryBase ibFolder in ifRoot._Contents) { @@ -410,7 +413,7 @@ namespace libsecondlife.InventorySystem /// /// Clear Folders /// Clear Items - internal void FolderClearContents(InventoryFolder iFolder, bool Folders, bool Items) + public void FolderClearContents(InventoryFolder iFolder, bool Folders, bool Items) { // Need to recursively do this... while( iFolder._Contents.Count > 0 ) @@ -682,22 +685,64 @@ namespace libsecondlife.InventorySystem } /// - /// Request the download of a folder's contents + /// Append a request to the end of the queue. /// /// - internal void RequestFolder(DownloadRequest_Folder dr) + internal void FolderRequestAppend(DownloadRequest_Folder dr) { - lock (FolderDownloadStatus) + // Add new request to the end of the queue + lock (FolderRequests) { - FolderDownloadStatus[dr.FolderID] = dr; + FolderRequests.Add(dr); } - Packet packet = InvPacketHelper.FetchInventoryDescendents( - dr.FolderID - , dr.FetchFolders - , dr.FetchItems); + FolderRequestBegin(); + } - slClient.Network.SendPacket(packet); + /// + /// If not currently downloading a request, dequeue the next request and start it. + /// + internal void FolderRequestBegin() + { + // Wait until it's safe to be modifying what is currently downloading. + CurrentlyDownloadingMutex.WaitOne(); + + // If we not already downloading stuff, then lets start + if (CurrentlyDownloadingAFolder == false) + { + // Dequeue the first thing in the queue + lock (FolderRequests) + { + if (FolderRequests.Count > 0) + { + CurrentlyDownloadingRequest = FolderRequests[0]; + FolderRequests.RemoveAt(0); + } + else + { + // Nothing to do + + // Release so that we can let other things look at and modify what is currently downloading. + CurrentlyDownloadingMutex.ReleaseMutex(); + + return; + } + } + + // Mark that we're currently downloading + CurrentlyDownloadingAFolder = true; + + // Download! + Packet packet = InvPacketHelper.FetchInventoryDescendents( + CurrentlyDownloadingRequest.FolderID + , CurrentlyDownloadingRequest.FetchFolders + , CurrentlyDownloadingRequest.FetchItems); + + slClient.Network.SendPacket(packet); + } + + // Release so that we can let other things look at and modify what is currently downloading. + CurrentlyDownloadingMutex.ReleaseMutex(); } /// @@ -738,16 +783,48 @@ namespace libsecondlife.InventorySystem LLUUID imSessionID, DateTime timestamp, string message, MainAvatar.InstantMessageOnline offline, byte[] binaryBucket) { - if ((dialog == MainAvatar.InstantMessageDialog.InventoryOffered) && (OnInventoryItemReceived != null)) + Console.WriteLine(Helpers.FieldToHexString(binaryBucket, "")); + + if ((dialog == MainAvatar.InstantMessageDialog.InventoryOffered) && ((OnInventoryItemReceived != null) || (OnInventoryFolderReceived !=null))) { sbyte IncomingItemType = (sbyte)binaryBucket[0]; - LLUUID IncomingItemID = new LLUUID(binaryBucket, 1); + LLUUID IncomingUUID = new LLUUID(binaryBucket, 1); // Update root folders InventoryFolder root = GetRootFolder(); if (root.GetContents().Count == 0) { - root.RequestDownloadContents(false, true, false, false).RequestComplete.WaitOne(3000, false); + root.RequestDownloadContents(false, true, false).RequestComplete.WaitOne(3000, false); + } + + // Handle the case of the incoming inventory folder + if (IncomingItemType == (sbyte)InventoryManager.InventoryType.Folder) + { + InventoryFolder iFolder = null; + int numAttempts = 2; + while( numAttempts-- > 0 ) + { + foreach( InventoryBase ib in root.GetContents() ) + { + if (ib is InventoryFolder) + { + InventoryFolder tiFolder = (InventoryFolder)ib; + if (tiFolder.FolderID == IncomingUUID) + { + iFolder = tiFolder; + break; + } + } + } + if (iFolder != null) + { + OnInventoryFolderReceived(fromAgentID, fromAgentName, parentEstateID, regionID, position, timestamp, iFolder); + return; + } else { + Thread.Sleep(500); + root.RequestDownloadContents(false, true, false).RequestComplete.WaitOne(3000, false); + } + } } // Make sure we have a folder lookup by type table ready. @@ -776,37 +853,43 @@ namespace libsecondlife.InventorySystem InventoryFolder incomingFolder = FolderByType[IncomingItemType]; InventoryItem incomingItem = null; - // lock just incade another item comes into the same directory while processing this one. + // lock just incase another item comes into the same directory while processing this one. lock (incomingFolder) { // Refresh contents of receiving folder - incomingFolder.RequestDownloadContents(false, false, true, false).RequestComplete.WaitOne(3000, false); + incomingFolder.RequestDownloadContents(false, false, true).RequestComplete.WaitOne(3000, false); - // Search folder for incoming item - foreach (InventoryBase ib2 in incomingFolder.GetContents()) + int numAttempts = 2; + while( numAttempts-- > 0 ) { - if (ib2 is InventoryItem) + // Search folder for incoming item + foreach (InventoryBase ib2 in incomingFolder.GetContents()) { - InventoryItem iItem = (InventoryItem)ib2; - - if (iItem.ItemID == IncomingItemID) + if (ib2 is InventoryItem) { - incomingItem = iItem; - break; + InventoryItem tiItem = (InventoryItem)ib2; + + if (tiItem.ItemID == IncomingUUID) + { + incomingItem = tiItem; + break; + } } } + // If found, send out notification + if (incomingItem != null) + { + OnInventoryItemReceived(fromAgentID, fromAgentName, parentEstateID, regionID, position, timestamp, incomingItem); + return; + } + else + { + incomingFolder.RequestDownloadContents(false, false, true).RequestComplete.WaitOne(3000, false); + } } } + slClient.Log("Incoming item/folder [" + IncomingUUID.ToStringHyphenated() + "] not found in inventory.", Helpers.LogLevel.Error); - // If found, send out notification - if (incomingItem != null) - { - OnInventoryItemReceived(fromAgentID, fromAgentName, parentEstateID, regionID, position, timestamp, incomingItem); - } - else - { - slClient.Log("Incoming item not found in inventory.", Helpers.LogLevel.Error); - } } } @@ -877,18 +960,20 @@ namespace libsecondlife.InventorySystem // The UUID of this folder. LLUUID uuidFolderID = reply.AgentData.FolderID; - // Get the original Descendent Request for this Packet - DownloadRequest_Folder dr = null; - lock (FolderDownloadStatus) + // Wait until it's safe to be looking at what is currently downloading. + CurrentlyDownloadingMutex.WaitOne(); + + // Make sure this request matches the one we believe is the currently downloading request + if( CurrentlyDownloadingRequest.FolderID != uuidFolderID ) { - if (FolderDownloadStatus.ContainsKey(uuidFolderID)) - { - dr = (DownloadRequest_Folder)FolderDownloadStatus[uuidFolderID]; - } - else - { - slClient.Log("Received an inventory descendent packet for a folder (" + uuidFolderID.ToStringHyphenated() + ") that was not in FolderDownloadStatus.", Helpers.LogLevel.Info); - } + // Release so that we can let other things look at and modify what is currently downloading. + CurrentlyDownloadingMutex.ReleaseMutex(); + + // Log problem + slClient.Log("Received an inventory descendent packet for a folder (" + uuidFolderID.ToStringHyphenated() + ") that is not the currently downloading request.", Helpers.LogLevel.Info); + + // Just discard this packet... + return; } // Get the Inventory folder that we'll be updating @@ -901,191 +986,181 @@ namespace libsecondlife.InventorySystem int iDescendentsExpected = reply.AgentData.Descendents; int iDescendentsReceivedThisBlock = 0; - lock (slClient.Inventory) + #region Handle Child Items + foreach (InventoryDescendentsPacket.ItemDataBlock itemBlock in reply.ItemData) { - - #region Handle Child Items - foreach (InventoryDescendentsPacket.ItemDataBlock itemBlock in reply.ItemData) + // There is always an item block, even if there isn't any items + // the "filler" block will not have a name + if (itemBlock.Name.Length != 0) { - // There is always an item block, even if there isn't any items - // the "filler" block will not have a name - if (itemBlock.Name.Length != 0) + iDescendentsReceivedThisBlock++; + + if (itemBlock.ItemID == LLUUID.Zero) { - iDescendentsReceivedThisBlock++; - - if (itemBlock.ItemID == LLUUID.Zero) - { - // this shouldn't ever happen, unless you've uploaded an invalid item - // to yourself while developping inventory code :-( - } - else - { - InventoryItem TempInvItem = new InventoryItem(this, itemBlock); - - if (InvFolderUpdating._Contents.Contains(TempInvItem) == false) - { - if ((TempInvItem.InvType == 7) && (TempInvItem.Type == (sbyte)Asset.AssetType.Notecard)) - { - InventoryItem temp = new InventoryNotecard(this, TempInvItem); - TempInvItem = temp; - } - - if ((TempInvItem.InvType == 0) && (TempInvItem.Type == (sbyte)Asset.AssetType.Texture)) - { - InventoryItem temp = new InventoryImage(this, TempInvItem); - TempInvItem = temp; - } - - if ((TempInvItem.InvType == 10) && (TempInvItem.Type == (sbyte)Asset.AssetType.LSLText)) - { - InventoryItem temp = new InventoryScript(this, TempInvItem); - TempInvItem = temp; - } - - if ((TempInvItem.InvType == 18) && - ( - (TempInvItem.Type == (sbyte)Asset.AssetType.Bodypart) - || (TempInvItem.Type == (sbyte)Asset.AssetType.Clothing) - ) - ) - { - InventoryItem temp = new InventoryWearable(this, TempInvItem); - TempInvItem = temp; - } - - InvFolderUpdating._Contents.Add(TempInvItem); - } - } + // this shouldn't ever happen, unless you've uploaded an invalid item + // to yourself while developping inventory code :-( } - } - #endregion - - #region Handle Child Folders - foreach (InventoryDescendentsPacket.FolderDataBlock folderBlock in reply.FolderData) - { - String IncomingName = System.Text.Encoding.UTF8.GetString(folderBlock.Name).Trim().Replace("\0", ""); - LLUUID IncomingFolderID = folderBlock.FolderID; - LLUUID IncomingParentID = folderBlock.ParentID; - sbyte IncomingType = folderBlock.Type; - - // There is always an folder block, even if there isn't any folders - // the "filler" block will not have a name - if (folderBlock.Name.Length != 0) + else { - iDescendentsReceivedThisBlock++; + InventoryItem TempInvItem = new InventoryItem(this, itemBlock); - // See if the Incoming Folder already exists locally - if (FoldersByUUID.ContainsKey(IncomingFolderID)) + if (InvFolderUpdating._Contents.Contains(TempInvItem) == false) { - InventoryFolder existingFolder = FoldersByUUID[IncomingFolderID]; - existingFolder._Name = IncomingName; - existingFolder._Type = IncomingType; - - // Check if parent of existing is the same as the incoming - if (!existingFolder.ParentID.Equals(IncomingParentID)) + #region Create an instance of the appriopriate Inventory class + if ((TempInvItem.InvType == 7) && (TempInvItem.Type == (sbyte)Asset.AssetType.Notecard)) { - // Remove existing from old parent - if (FoldersByUUID.ContainsKey(existingFolder.ParentID)) - { - InventoryFolder ExistingParent = FoldersByUUID[existingFolder.ParentID]; - if (ExistingParent._Contents.Contains(existingFolder)) - { - ExistingParent._Contents.Remove(existingFolder); - } - } - - // Set existings parent to new - existingFolder._ParentID = IncomingParentID; - - // Connect existing folder to parent specified in new - if (FoldersByUUID.ContainsKey(IncomingParentID)) - { - InventoryFolder ExistingParent = FoldersByUUID[IncomingParentID]; - if (!ExistingParent._Contents.Contains(existingFolder)) - { - ExistingParent._Contents.Add(existingFolder); - } - } - } - } - else - { - InventoryFolder TempInvFolder = new InventoryFolder(this, IncomingName, IncomingFolderID, IncomingParentID, IncomingType); - - // Add folder to Parent - if (InvFolderUpdating._Contents.Contains(TempInvFolder) == false) - { - InvFolderUpdating._Contents.Add(TempInvFolder); + InventoryItem temp = new InventoryNotecard(this, TempInvItem); + TempInvItem = temp; } - // Add folder to local cache lookup - FoldersByUUID[TempInvFolder.FolderID] = TempInvFolder; - - } - - - // Do we recurse? - if (dr.Recurse) - { - // It's not the root, should be safe to "recurse" - if (!IncomingFolderID.Equals(slClient.Self.InventoryRootFolderUUID)) + if ((TempInvItem.InvType == 0) && (TempInvItem.Type == (sbyte)Asset.AssetType.Texture)) { - // Check if a download for this folder is already queued - bool alreadyQueued = false; - lock (FolderRequestQueue) - { - foreach (DownloadRequest_Folder adr in FolderRequestQueue) - { - if (adr.FolderID == IncomingFolderID) - { - alreadyQueued = true; - break; - } - } - // If not, then queue the stucker - if (!alreadyQueued) - { - FolderRequestQueue.Enqueue(new DownloadRequest_Folder(IncomingFolderID, dr.Recurse, dr.FetchFolders, dr.FetchItems)); - } - } + InventoryItem temp = new InventoryImage(this, TempInvItem); + TempInvItem = temp; } - } - } - } - #endregion - // Update total number of descendants expected , and update the total downloaded - dr.Expected = iDescendentsExpected; - dr.Received += iDescendentsReceivedThisBlock; - dr.LastReceivedAtTick = Environment.TickCount; + if ((TempInvItem.InvType == 10) && (TempInvItem.Type == (sbyte)Asset.AssetType.LSLText)) + { + InventoryItem temp = new InventoryScript(this, TempInvItem); + TempInvItem = temp; + } - // Check if we're finished - if (dr.Received >= dr.Expected) - { - // Looks like after updating, we have all the descendents, - // remove from folder status. - lock (FolderDownloadStatus) - { - FolderDownloadStatus.Remove(uuidFolderID); - } - dr.RequestComplete.Set(); - if (OnRequestDownloadFinishedEvent != null) - { - DownloadRequest_EventArgs e = new DownloadRequest_EventArgs(); - e.DownloadRequest = dr; - FireRequestDownloadFinishedEvent(InvFolderUpdating, e); - } + if ((TempInvItem.InvType == 18) && + ( + (TempInvItem.Type == (sbyte)Asset.AssetType.Bodypart) + || (TempInvItem.Type == (sbyte)Asset.AssetType.Clothing) + ) + ) + { + InventoryItem temp = new InventoryWearable(this, TempInvItem); + TempInvItem = temp; + } + #endregion - // If there's any more download requests queued, grab one, and go - lock (FolderRequestQueue) - { - if (FolderRequestQueue.Count > 0) - { - RequestFolder(FolderRequestQueue.Dequeue()); + InvFolderUpdating._Contents.Add(TempInvItem); } } } } + #endregion + + #region Handle Child Folders + foreach (InventoryDescendentsPacket.FolderDataBlock folderBlock in reply.FolderData) + { + String IncomingName = System.Text.Encoding.UTF8.GetString(folderBlock.Name).Trim().Replace("\0", ""); + LLUUID IncomingFolderID = folderBlock.FolderID; + LLUUID IncomingParentID = folderBlock.ParentID; + sbyte IncomingType = folderBlock.Type; + + // There is always an folder block, even if there isn't any folders + // the "filler" block will not have a name + if (folderBlock.Name.Length != 0) + { + iDescendentsReceivedThisBlock++; + + // See if the Incoming Folder already exists locally + if (FoldersByUUID.ContainsKey(IncomingFolderID)) + { + InventoryFolder existingFolder = FoldersByUUID[IncomingFolderID]; + existingFolder._Name = IncomingName; + existingFolder._Type = IncomingType; + + // Check if parent of existing is the same as the incoming + if (!existingFolder.ParentID.Equals(IncomingParentID)) + { + // Remove existing from old parent + if (FoldersByUUID.ContainsKey(existingFolder.ParentID)) + { + InventoryFolder ExistingParent = FoldersByUUID[existingFolder.ParentID]; + if (ExistingParent._Contents.Contains(existingFolder)) + { + ExistingParent._Contents.Remove(existingFolder); + } + } + + // Set existings parent to new + existingFolder._ParentID = IncomingParentID; + + // Connect existing folder to parent specified in new + if (FoldersByUUID.ContainsKey(IncomingParentID)) + { + InventoryFolder ExistingParent = FoldersByUUID[IncomingParentID]; + if (!ExistingParent._Contents.Contains(existingFolder)) + { + ExistingParent._Contents.Add(existingFolder); + } + } + } + } + else + { + InventoryFolder TempInvFolder = new InventoryFolder(this, IncomingName, IncomingFolderID, IncomingParentID, IncomingType); + + // Add folder to Parent + if (InvFolderUpdating._Contents.Contains(TempInvFolder) == false) + { + InvFolderUpdating._Contents.Add(TempInvFolder); + } + + // Add folder to local cache lookup + FoldersByUUID[TempInvFolder.FolderID] = TempInvFolder; + + } + + + // Do we recurse? + if (CurrentlyDownloadingRequest.Recurse) + { + // It's not the root, should be safe to "recurse" + if (!IncomingFolderID.Equals(slClient.Self.InventoryRootFolderUUID)) + { + lock (FolderRequests) + { + FolderRequests.Insert(0, new DownloadRequest_Folder(IncomingFolderID, CurrentlyDownloadingRequest.Recurse, CurrentlyDownloadingRequest.FetchFolders, CurrentlyDownloadingRequest.FetchItems)); + } + } + } + } + } + #endregion + + // Update total number of descendants expected , and update the total downloaded + CurrentlyDownloadingRequest.Expected = iDescendentsExpected; + CurrentlyDownloadingRequest.Received += iDescendentsReceivedThisBlock; + CurrentlyDownloadingRequest.LastReceivedAtTick = Environment.TickCount; + + // Check if we're finished + if (CurrentlyDownloadingRequest.Received >= CurrentlyDownloadingRequest.Expected) + { + // Looks like after updating, we have all the immeadiate descendents for the current request, + // remove from folder status. + lock (FolderRequests) + { + FolderRequests.Remove(CurrentlyDownloadingRequest); + } + + // Singal anyone that was waiting for this request to finish + CurrentlyDownloadingRequest.RequestComplete.Set(); + + // Raise an event for anyone that cares to listen for downloaded folder events + if (OnRequestDownloadFinishedEvent != null) + { + DownloadRequest_EventArgs e = new DownloadRequest_EventArgs(); + e.DownloadRequest = CurrentlyDownloadingRequest; + FireRequestDownloadFinishedEvent(InvFolderUpdating, e); + } + + // Set Inventory Manager state to reflect that we're done with the current download + CurrentlyDownloadingAFolder = false; + CurrentlyDownloadingRequest = null; + } + + // Release so that we can let other things look at and modify what is currently downloading. + CurrentlyDownloadingMutex.ReleaseMutex(); + + + // If there's any more download requests queued, grab one, and go + FolderRequestBegin(); } #endregion }