/// <summary> /// Loads in inventory cache file into the inventory structure. Note only valid to call after login has been successful. /// </summary> /// <param name="filename">Name of the cache file to load</param> /// <returns>The number of inventory items sucessfully reconstructed into the inventory node tree</returns> public int RestoreFromDisk(string filename) { List <InventoryNode> nodes = new List <InventoryNode>(); int item_count = 0; try { if (!File.Exists(filename)) { return(-1); } using (Stream stream = File.Open(filename, FileMode.Open)) { BinaryFormatter bformatter = new BinaryFormatter(); while (stream.Position < stream.Length) { OpenMetaverse.InventoryNode node = (InventoryNode)bformatter.Deserialize(stream); nodes.Add(node); item_count++; } } } catch (Exception e) { Logger.Log("Error accessing inventory cache file :" + e.Message, Helpers.LogLevel.Error); return(-1); } Logger.Log("Read " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); item_count = 0; List <InventoryNode> del_nodes = new List <InventoryNode>(); //nodes that we have processed and will delete List <UUID> dirty_folders = new List <UUID>(); // Tainted folders that we will not restore items into // Because we could get child nodes before parents we must itterate around and only add nodes who have // a parent already in the list because we must update both child and parent to link together // But sometimes we have seen orphin nodes due to bad/incomplete data when caching so we have an emergency abort route int stuck = 0; while (nodes.Count != 0 && stuck < 5) { foreach (InventoryNode node in nodes) { InventoryNode pnode; if (node.ParentID == UUID.Zero) { //We don't need the root nodes "My Inventory" etc as they will already exist for the correct // user of this cache. del_nodes.Add(node); item_count--; } else if (Items.TryGetValue(node.Data.UUID, out pnode)) { //We already have this it must be a folder if (node.Data is InventoryFolder) { InventoryFolder cache_folder = (InventoryFolder)node.Data; InventoryFolder server_folder = (InventoryFolder)pnode.Data; if (cache_folder.Version != server_folder.Version) { Logger.DebugLog("Inventory Cache/Server version mismatch on " + node.Data.Name + " " + cache_folder.Version.ToString() + " vs " + server_folder.Version.ToString()); pnode.NeedsUpdate = true; dirty_folders.Add(node.Data.UUID); } else { pnode.NeedsUpdate = false; } del_nodes.Add(node); } } else if (Items.TryGetValue(node.ParentID, out pnode)) { if (node.Data != null) { // If node is folder, and it does not exist in skeleton, mark it as // dirty and don't process nodes that belong to it if (node.Data is InventoryFolder && !(Items.ContainsKey(node.Data.UUID))) { dirty_folders.Add(node.Data.UUID); } //Only add new items, this is most likely to be run at login time before any inventory //nodes other than the root are populated. Don't add non existing folders. if (!Items.ContainsKey(node.Data.UUID) && !dirty_folders.Contains(pnode.Data.UUID) && !(node.Data is InventoryFolder)) { Items.Add(node.Data.UUID, node); node.Parent = pnode; //Update this node with its parent pnode.Nodes.Add(node.Data.UUID, node); // Add to the parents child list item_count++; } } del_nodes.Add(node); } } if (del_nodes.Count == 0) { stuck++; } else { stuck = 0; } //Clean up processed nodes this loop around. foreach (InventoryNode node in del_nodes) { nodes.Remove(node); } del_nodes.Clear(); } Logger.Log("Reassembled " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); return(item_count); }
/// <summary> /// Loads in inventory cache file into the inventory structure. Note only valid to call after login has been successful. /// </summary> /// <param name="filename">Name of the cache file to load</param> public void read_inventory_cache(string filename) { List <InventoryNode> nodes = new List <InventoryNode>(); int item_count = 0; try { if (!File.Exists(filename)) { return; } Stream stream = File.Open(filename, FileMode.Open); BinaryFormatter bformatter = new BinaryFormatter(); while (stream.Position < stream.Length) { OpenMetaverse.InventoryNode node = (InventoryNode)bformatter.Deserialize(stream); nodes.Add(node); item_count++; } stream.Close(); } catch (Exception e) { Logger.Log("Error accessing inventory cache file :" + e.Message, Helpers.LogLevel.Error); return; } Logger.Log("Read " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); item_count = 0; List <InventoryNode> del_nodes = new List <InventoryNode>(); // Becuase we could get child nodes before parents we must itterate around and only add nodes who have // a parent already in the list because we must update both child and parent to link together while (nodes.Count != 0) { foreach (InventoryNode node in nodes) { InventoryNode pnode; if (node.ParentID == UUID.Zero) { //We don't need the root nodes "My Inventory" etc as they will already exist for the correct // user of this cache. del_nodes.Add(node); } else if (Items.TryGetValue(node.ParentID, out pnode)) { if (node.Data != null) { //Only add new items, this is most likely to be run at login time before any inventory //nodes other than the root are populated. if (!Items.ContainsKey(node.Data.UUID)) { Items.Add(node.Data.UUID, node); node.Parent = pnode; //Update this node with its parent pnode.Nodes.Add(node.Data.UUID, node); // Add to the parents child list item_count++; } } del_nodes.Add(node); } } //Clean up processed nodes this loop around. foreach (InventoryNode node in del_nodes) { nodes.Remove(node); } del_nodes.Clear(); } Logger.Log("Reassembled " + item_count.ToString() + " items from inventory cache file", Helpers.LogLevel.Info); }