private void InventoryDescendentsHandler(Packet packet, Simulator simulator)
{
InventoryDescendentsPacket reply = (InventoryDescendentsPacket)packet;
if (reply.AgentData.Descendents > 0)
{
// InventoryDescendantsReply sends a null folder if the parent doesnt contain any folders
if (reply.FolderData[0].FolderID != UUID.Zero)
{
// Iterate folders in this packet
for (int i = 0; i < reply.FolderData.Length; i++)
{
InventoryFolder folder = new InventoryFolder(reply.FolderData[i].FolderID);
folder.ParentUUID = reply.FolderData[i].ParentID;
folder.Name = Utils.BytesToString(reply.FolderData[i].Name);
folder.PreferredType = (AssetType)reply.FolderData[i].Type;
folder.OwnerID = reply.AgentData.OwnerID;
_Store[folder.UUID] = folder;
}
}
// InventoryDescendantsReply sends a null item if the parent doesnt contain any items.
if (reply.ItemData[0].ItemID != UUID.Zero)
{
// Iterate items in this packet
for (int i = 0; i < reply.ItemData.Length; i++)
{
if (reply.ItemData[i].ItemID != UUID.Zero)
{
InventoryItem item;
/*
* Objects that have been attached in-world prior to being stored on the
* asset server are stored with the InventoryType of 0 (Texture)
* instead of 17 (Attachment)
*
* This corrects that behavior by forcing Object Asset types that have an
* invalid InventoryType with the proper InventoryType of Attachment.
*/
if ((AssetType)reply.ItemData[i].Type == AssetType.Object
&& (InventoryType)reply.ItemData[i].InvType == InventoryType.Texture)
{
item = CreateInventoryItem(InventoryType.Attachment, reply.ItemData[i].ItemID);
item.InventoryType = InventoryType.Attachment;
}
else
{
item = CreateInventoryItem((InventoryType)reply.ItemData[i].InvType, reply.ItemData[i].ItemID);
item.InventoryType = (InventoryType)reply.ItemData[i].InvType;
}
item.ParentUUID = reply.ItemData[i].FolderID;
item.CreatorID = reply.ItemData[i].CreatorID;
item.AssetType = (AssetType)reply.ItemData[i].Type;
item.AssetUUID = reply.ItemData[i].AssetID;
item.CreationDate = Utils.UnixTimeToDateTime((uint)reply.ItemData[i].CreationDate);
item.Description = Utils.BytesToString(reply.ItemData[i].Description);
item.Flags = reply.ItemData[i].Flags;
item.Name = Utils.BytesToString(reply.ItemData[i].Name);
item.GroupID = reply.ItemData[i].GroupID;
item.GroupOwned = reply.ItemData[i].GroupOwned;
item.Permissions = new Permissions(
reply.ItemData[i].BaseMask,
reply.ItemData[i].EveryoneMask,
reply.ItemData[i].GroupMask,
reply.ItemData[i].NextOwnerMask,
reply.ItemData[i].OwnerMask);
item.SalePrice = reply.ItemData[i].SalePrice;
item.SaleType = (SaleType)reply.ItemData[i].SaleType;
item.OwnerID = reply.AgentData.OwnerID;
_Store[item.UUID] = item;
}
}
}
}
InventoryFolder parentFolder = null;
if (_Store.Contains(reply.AgentData.FolderID) &&
_Store[reply.AgentData.FolderID] is InventoryFolder)
{
parentFolder = _Store[reply.AgentData.FolderID] as InventoryFolder;
}
else
{
Logger.Log("Don't have a reference to FolderID " + reply.AgentData.FolderID.ToString() +
" or it is not a folder", Helpers.LogLevel.Error, _Client);
return;
}
if (reply.AgentData.Version < parentFolder.Version)
{
Logger.Log("Got an outdated InventoryDescendents packet for folder " + parentFolder.Name +
", this version = " + reply.AgentData.Version + ", latest version = " + parentFolder.Version,
Helpers.LogLevel.Warning, _Client);
return;
}
parentFolder.Version = reply.AgentData.Version;
// FIXME: reply.AgentData.Descendants is not parentFolder.DescendentCount if we didn't
// request items and folders
parentFolder.DescendentCount = reply.AgentData.Descendents;
#region FindObjectsByPath Handling
if (_Searches.Count > 0)
{
lock (_Searches)
{
StartSearch:
// Iterate over all of the outstanding searches
for (int i = 0; i < _Searches.Count; i++)
{
InventorySearch search = _Searches[i];
List<InventoryBase> folderContents = _Store.GetContents(search.Folder);
// Iterate over all of the inventory objects in the base search folder
for (int j = 0; j < folderContents.Count; j++)
{
// Check if this inventory object matches the current path node
if (folderContents[j].Name == search.Path[search.Level])
{
if (search.Level == search.Path.Length - 1)
{
Logger.DebugLog("Finished path search of " + String.Join("/", search.Path), _Client);
// This is the last node in the path, fire the callback and clean up
if (OnFindObjectByPath != null)
{
try { OnFindObjectByPath(String.Join("/", search.Path), folderContents[j].UUID); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); }
}
// Remove this entry and restart the loop since we are changing the collection size
_Searches.RemoveAt(i);
goto StartSearch;
}
else
{
// We found a match but it is not the end of the path, request the next level
Logger.DebugLog(String.Format("Matched level {0}/{1} in a path search of {2}",
search.Level, search.Path.Length - 1, String.Join("/", search.Path)), _Client);
search.Folder = folderContents[j].UUID;
search.Level++;
_Searches[i] = search;
RequestFolderContents(search.Folder, search.Owner, true, true,
InventorySortOrder.ByName);
}
}
}
}
}
}
#endregion FindObjectsByPath Handling
// Callback for inventory folder contents being updated
if (OnFolderUpdated != null)
{
try { OnFolderUpdated(parentFolder.UUID); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); }
}
}