2007-07-13 14:49:36 +00:00
/ *
2008-07-21 21:12:59 +00:00
* Copyright ( c ) 2007 - 2008 , openmetaverse . org
2007-07-13 14:49:36 +00:00
* All rights reserved .
*
* - Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* - Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
2008-07-21 21:12:59 +00:00
* - Neither the name of the openmetaverse . org nor the names
2007-07-13 14:49:36 +00:00
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
* /
using System ;
using System.Collections.Generic ;
2009-02-26 20:41:39 +00:00
using System.IO ;
using System.Runtime.Serialization.Formatters.Binary ;
using System.Runtime.Serialization ;
2008-08-14 04:09:27 +00:00
2008-07-21 21:12:59 +00:00
namespace OpenMetaverse
2007-07-13 14:49:36 +00:00
{
2007-09-10 10:20:30 +00:00
/// <summary>
2008-08-21 01:19:06 +00:00
/// Exception class to identify inventory exceptions
2007-07-13 14:49:36 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
public class InventoryException : Exception
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
public InventoryException ( string message )
: base ( message ) { }
}
2008-07-29 21:36:53 +00:00
2008-08-21 01:19:06 +00:00
/// <summary>
/// Responsible for maintaining inventory structure. Inventory constructs nodes
/// and manages node children as is necessary to maintain a coherant hirarchy.
/// Other classes should not manipulate or create InventoryNodes explicitly. When
/// A node's parent changes (when a folder is moved, for example) simply pass
/// Inventory the updated InventoryFolder and it will make the appropriate changes
/// to its internal representation.
/// </summary>
public class Inventory
{
2009-10-29 09:39:43 +00:00
/// <summary>The event subscribers, null of no subscribers</summary>
private EventHandler < InventoryObjectUpdatedEventArgs > m_InventoryObjectUpdated ;
///<summary>Raises the InventoryObjectUpdated Event</summary>
/// <param name="e">A InventoryObjectUpdatedEventArgs object containing
/// the data sent from the simulator</param>
protected virtual void OnInventoryObjectUpdated ( InventoryObjectUpdatedEventArgs e )
{
EventHandler < InventoryObjectUpdatedEventArgs > handler = m_InventoryObjectUpdated ;
if ( handler ! = null )
handler ( this , e ) ;
}
2008-08-14 04:09:27 +00:00
2009-10-29 09:39:43 +00:00
/// <summary>Thread sync lock object</summary>
private readonly object m_InventoryObjectUpdatedLock = new object ( ) ;
/// <summary>Raised when the simulator sends us data containing
/// ...</summary>
public event EventHandler < InventoryObjectUpdatedEventArgs > InventoryObjectUpdated
{
add { lock ( m_InventoryObjectUpdatedLock ) { m_InventoryObjectUpdated + = value ; } }
remove { lock ( m_InventoryObjectUpdatedLock ) { m_InventoryObjectUpdated - = value ; } }
}
/// <summary>The event subscribers, null of no subscribers</summary>
private EventHandler < InventoryObjectRemovedEventArgs > m_InventoryObjectRemoved ;
///<summary>Raises the InventoryObjectRemoved Event</summary>
/// <param name="e">A InventoryObjectRemovedEventArgs object containing
/// the data sent from the simulator</param>
protected virtual void OnInventoryObjectRemoved ( InventoryObjectRemovedEventArgs e )
{
EventHandler < InventoryObjectRemovedEventArgs > handler = m_InventoryObjectRemoved ;
if ( handler ! = null )
handler ( this , e ) ;
}
/// <summary>Thread sync lock object</summary>
private readonly object m_InventoryObjectRemovedLock = new object ( ) ;
2008-07-29 21:36:53 +00:00
2009-10-29 09:39:43 +00:00
/// <summary>Raised when the simulator sends us data containing
/// ...</summary>
public event EventHandler < InventoryObjectRemovedEventArgs > InventoryObjectRemoved
{
add { lock ( m_InventoryObjectRemovedLock ) { m_InventoryObjectRemoved + = value ; } }
remove { lock ( m_InventoryObjectRemovedLock ) { m_InventoryObjectRemoved - = value ; } }
}
/// <summary>The event subscribers, null of no subscribers</summary>
private EventHandler < InventoryObjectAddedEventArgs > m_InventoryObjectAdded ;
///<summary>Raises the InventoryObjectAdded Event</summary>
/// <param name="e">A InventoryObjectAddedEventArgs object containing
/// the data sent from the simulator</param>
protected virtual void OnInventoryObjectAdded ( InventoryObjectAddedEventArgs e )
{
EventHandler < InventoryObjectAddedEventArgs > handler = m_InventoryObjectAdded ;
if ( handler ! = null )
handler ( this , e ) ;
}
/// <summary>Thread sync lock object</summary>
private readonly object m_InventoryObjectAddedLock = new object ( ) ;
/// <summary>Raised when the simulator sends us data containing
/// ...</summary>
public event EventHandler < InventoryObjectAddedEventArgs > InventoryObjectAdded
{
add { lock ( m_InventoryObjectAddedLock ) { m_InventoryObjectAdded + = value ; } }
remove { lock ( m_InventoryObjectAddedLock ) { m_InventoryObjectAdded - = value ; } }
}
2008-08-12 05:55:42 +00:00
/// <summary>
2008-08-21 01:19:06 +00:00
/// The root folder of this avatars inventory
2008-08-12 05:55:42 +00:00
/// </summary>
2008-07-29 21:36:53 +00:00
public InventoryFolder RootFolder
{
2008-08-21 01:19:06 +00:00
get { return RootNode . Data as InventoryFolder ; }
set
2008-08-05 05:07:53 +00:00
{
2008-08-21 01:19:06 +00:00
UpdateNodeFor ( value ) ;
_RootNode = Items [ value . UUID ] ;
2008-08-05 05:07:53 +00:00
}
}
2007-07-13 14:49:36 +00:00
/// <summary>
2008-08-21 01:19:06 +00:00
/// The default shared library folder
2007-07-13 14:49:36 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
public InventoryFolder LibraryFolder
2008-07-29 23:38:07 +00:00
{
2008-08-21 01:19:06 +00:00
get { return LibraryRootNode . Data as InventoryFolder ; }
set
2008-05-05 10:32:47 +00:00
{
2008-08-21 01:19:06 +00:00
UpdateNodeFor ( value ) ;
_LibraryRootNode = Items [ value . UUID ] ;
2008-05-05 10:32:47 +00:00
}
}
2008-08-21 01:19:06 +00:00
private InventoryNode _LibraryRootNode ;
private InventoryNode _RootNode ;
2007-07-13 14:49:36 +00:00
/// <summary>
2008-08-21 01:19:06 +00:00
/// The root node of the avatars inventory
2007-07-13 14:49:36 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
public InventoryNode RootNode
2007-11-06 09:26:10 +00:00
{
2009-08-12 23:45:52 +00:00
get { return _RootNode ; }
2007-11-06 09:26:10 +00:00
}
2007-07-13 14:49:36 +00:00
2008-05-05 10:32:47 +00:00
/// <summary>
2008-08-21 01:19:06 +00:00
/// The root node of the default shared library
2008-05-05 10:32:47 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
public InventoryNode LibraryRootNode
2008-05-05 10:32:47 +00:00
{
2009-08-12 23:45:52 +00:00
get { return _LibraryRootNode ; }
2008-05-05 10:32:47 +00:00
}
2008-08-21 01:19:06 +00:00
public UUID Owner {
get { return _Owner ; }
2007-07-13 14:49:36 +00:00
}
2008-08-21 01:19:06 +00:00
private UUID _Owner ;
2007-07-13 14:49:36 +00:00
2008-08-21 01:19:06 +00:00
private GridClient Client ;
2008-10-09 16:48:44 +00:00
//private InventoryManager Manager;
2009-06-27 20:51:14 +00:00
public Dictionary < UUID , InventoryNode > Items = new Dictionary < UUID , InventoryNode > ( ) ;
2008-08-14 04:09:27 +00:00
2008-08-21 01:19:06 +00:00
public Inventory ( GridClient client , InventoryManager manager )
: this ( client , manager , client . Self . AgentID ) { }
2008-08-14 04:09:27 +00:00
2008-08-21 01:19:06 +00:00
public Inventory ( GridClient client , InventoryManager manager , UUID owner )
{
Client = client ;
2008-10-09 16:48:44 +00:00
//Manager = manager;
2008-08-21 01:19:06 +00:00
_Owner = owner ;
if ( owner = = UUID . Zero )
Logger . Log ( "Inventory owned by nobody!" , Helpers . LogLevel . Warning , Client ) ;
Items = new Dictionary < UUID , InventoryNode > ( ) ;
2007-07-13 14:49:36 +00:00
}
2008-08-21 01:19:06 +00:00
public List < InventoryBase > GetContents ( InventoryFolder folder )
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
return GetContents ( folder . UUID ) ;
2008-07-29 21:36:53 +00:00
}
/// <summary>
2008-08-21 01:19:06 +00:00
/// Returns the contents of the specified folder
2008-07-29 21:36:53 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
/// <param name="folder">A folder's UUID</param>
/// <returns>The contents of the folder corresponding to <code>folder</code></returns>
/// <exception cref="InventoryException">When <code>folder</code> does not exist in the inventory</exception>
public List < InventoryBase > GetContents ( UUID folder )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
InventoryNode folderNode ;
if ( ! Items . TryGetValue ( folder , out folderNode ) )
throw new InventoryException ( "Unknown folder: " + folder ) ;
lock ( folderNode . Nodes . SyncRoot )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
List < InventoryBase > contents = new List < InventoryBase > ( folderNode . Nodes . Count ) ;
foreach ( InventoryNode node in folderNode . Nodes . Values )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
contents . Add ( node . Data ) ;
2007-07-13 14:49:36 +00:00
}
2008-08-21 01:19:06 +00:00
return contents ;
2008-08-12 05:55:42 +00:00
}
}
/// <summary>
2008-08-21 01:19:06 +00:00
/// Updates the state of the InventoryNode and inventory data structure that
/// is responsible for the InventoryObject. If the item was previously not added to inventory,
/// it adds the item, and updates structure accordingly. If it was, it updates the
/// InventoryNode, changing the parent node if <code>item.parentUUID</code> does
/// not match <code>node.Parent.Data.UUID</code>.
///
/// You can not set the inventory root folder using this method
2008-08-12 05:55:42 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
/// <param name="item">The InventoryObject to store</param>
public void UpdateNodeFor ( InventoryBase item )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
lock ( Items )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
InventoryNode itemParent = null ;
if ( item . ParentUUID ! = UUID . Zero & & ! Items . TryGetValue ( item . ParentUUID , out itemParent ) )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
// OK, we have no data on the parent, let's create a fake one.
InventoryFolder fakeParent = new InventoryFolder ( item . ParentUUID ) ;
fakeParent . DescendentCount = 1 ; // Dear god, please forgive me.
itemParent = new InventoryNode ( fakeParent ) ;
Items [ item . ParentUUID ] = itemParent ;
// Unfortunately, this breaks the nice unified tree
// while we're waiting for the parent's data to come in.
// As soon as we get the parent, the tree repairs itself.
2011-03-30 11:56:33 +00:00
//Logger.DebugLog("Attempting to update inventory child of " +
// item.ParentUUID.ToString() + " when we have no local reference to that folder", Client);
2008-08-21 01:19:06 +00:00
if ( Client . Settings . FETCH_MISSING_INVENTORY )
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
// Fetch the parent
List < UUID > fetchreq = new List < UUID > ( 1 ) ;
2009-10-29 09:39:43 +00:00
fetchreq . Add ( item . ParentUUID ) ;
2008-08-12 05:55:42 +00:00
}
}
2008-08-21 01:19:06 +00:00
InventoryNode itemNode ;
if ( Items . TryGetValue ( item . UUID , out itemNode ) ) // We're updating.
{
InventoryNode oldParent = itemNode . Parent ;
// Handle parent change
if ( oldParent = = null | | itemParent = = null | | itemParent . Data . UUID ! = oldParent . Data . UUID )
2008-08-12 05:55:42 +00:00
{
2008-08-21 01:19:06 +00:00
if ( oldParent ! = null )
2007-11-06 09:26:10 +00:00
{
2008-08-21 01:19:06 +00:00
lock ( oldParent . Nodes . SyncRoot )
oldParent . Nodes . Remove ( item . UUID ) ;
}
if ( itemParent ! = null )
{
lock ( itemParent . Nodes . SyncRoot )
itemParent . Nodes [ item . UUID ] = itemNode ;
2007-11-06 09:26:10 +00:00
}
2007-07-13 14:49:36 +00:00
}
2008-08-21 01:19:06 +00:00
itemNode . Parent = itemParent ;
2008-07-29 21:36:53 +00:00
2009-10-29 09:39:43 +00:00
if ( m_InventoryObjectUpdated ! = null )
{
OnInventoryObjectUpdated ( new InventoryObjectUpdatedEventArgs ( itemNode . Data , item ) ) ;
}
2008-07-29 21:36:53 +00:00
2008-08-21 01:19:06 +00:00
itemNode . Data = item ;
2008-08-14 04:09:27 +00:00
}
2008-08-21 01:19:06 +00:00
else // We're adding.
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
itemNode = new InventoryNode ( item , itemParent ) ;
Items . Add ( item . UUID , itemNode ) ;
2009-10-29 09:39:43 +00:00
if ( m_InventoryObjectAdded ! = null )
{
OnInventoryObjectAdded ( new InventoryObjectAddedEventArgs ( item ) ) ;
}
2007-07-13 14:49:36 +00:00
}
}
}
2008-08-21 01:19:06 +00:00
public InventoryNode GetNodeFor ( UUID uuid )
2008-03-31 21:31:02 +00:00
{
2008-08-21 01:19:06 +00:00
return Items [ uuid ] ;
2008-03-31 21:31:02 +00:00
}
2007-07-13 14:49:36 +00:00
/// <summary>
2008-08-21 01:19:06 +00:00
/// Removes the InventoryObject and all related node data from Inventory.
2007-07-13 14:49:36 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
/// <param name="item">The InventoryObject to remove.</param>
public void RemoveNodeFor ( InventoryBase item )
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
lock ( Items )
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
InventoryNode node ;
if ( Items . TryGetValue ( item . UUID , out node ) )
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
if ( node . Parent ! = null )
lock ( node . Parent . Nodes . SyncRoot )
node . Parent . Nodes . Remove ( item . UUID ) ;
Items . Remove ( item . UUID ) ;
2009-10-29 09:39:43 +00:00
if ( m_InventoryObjectRemoved ! = null )
{
OnInventoryObjectRemoved ( new InventoryObjectRemovedEventArgs ( item ) ) ;
}
2007-07-13 14:49:36 +00:00
}
2008-08-21 01:19:06 +00:00
// In case there's a new parent:
InventoryNode newParent ;
if ( Items . TryGetValue ( item . ParentUUID , out newParent ) )
2007-07-13 14:49:36 +00:00
{
2008-08-21 01:19:06 +00:00
lock ( newParent . Nodes . SyncRoot )
newParent . Nodes . Remove ( item . UUID ) ;
2007-07-13 14:49:36 +00:00
}
}
}
/// <summary>
2008-08-21 01:19:06 +00:00
/// Used to find out if Inventory contains the InventoryObject
/// specified by <code>uuid</code>.
2008-07-29 21:36:53 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
/// <param name="uuid">The UUID to check.</param>
/// <returns>true if inventory contains uuid, false otherwise</returns>
public bool Contains ( UUID uuid )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
return Items . ContainsKey ( uuid ) ;
2008-07-29 21:36:53 +00:00
}
2008-08-21 01:19:06 +00:00
public bool Contains ( InventoryBase obj )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
return Contains ( obj . UUID ) ;
2008-07-29 21:36:53 +00:00
}
2009-02-26 20:41:39 +00:00
/// <summary>
2009-06-27 20:51:14 +00:00
/// Saves the current inventory structure to a cache file
2009-02-26 20:41:39 +00:00
/// </summary>
/// <param name="filename">Name of the cache file to save to</param>
2009-06-27 20:51:14 +00:00
public void SaveToDisk ( string filename )
2009-06-28 16:13:58 +00:00
{
try
2009-06-27 20:51:14 +00:00
{
2009-08-12 23:45:52 +00:00
using ( Stream stream = File . Open ( filename , FileMode . Create ) )
2009-06-27 20:51:14 +00:00
{
2009-08-12 23:45:52 +00:00
BinaryFormatter bformatter = new BinaryFormatter ( ) ;
lock ( Items )
2009-06-27 20:51:14 +00:00
{
2009-08-12 23:45:52 +00:00
Logger . Log ( "Caching " + Items . Count . ToString ( ) + " inventory items to " + filename , Helpers . LogLevel . Info ) ;
foreach ( KeyValuePair < UUID , InventoryNode > kvp in Items )
{
bformatter . Serialize ( stream , kvp . Value ) ;
}
2009-06-27 20:51:14 +00:00
}
}
2009-06-28 16:13:58 +00:00
}
catch ( Exception e )
{
Logger . Log ( "Error saving inventory cache to disk :" + e . Message , Helpers . LogLevel . Error ) ;
2009-02-26 20:41:39 +00:00
}
}
/// <summary>
/// Loads in inventory cache file into the inventory structure. Note only valid to call after login has been successful.
/// </summary>
2009-06-28 16:13:58 +00:00
/// <param name="filename">Name of the cache file to load</param>
2009-06-27 20:51:14 +00:00
/// <returns>The number of inventory items sucessfully reconstructed into the inventory node tree</returns>
public int RestoreFromDisk ( string filename )
2009-02-26 20:41:39 +00:00
{
List < InventoryNode > nodes = new List < InventoryNode > ( ) ;
int item_count = 0 ;
try
{
if ( ! File . Exists ( filename ) )
2009-06-27 20:51:14 +00:00
return - 1 ;
2009-02-26 20:41:39 +00:00
2009-08-12 23:45:52 +00:00
using ( Stream stream = File . Open ( filename , FileMode . Open ) )
2009-02-26 20:41:39 +00:00
{
2009-08-12 23:45:52 +00:00
BinaryFormatter bformatter = new BinaryFormatter ( ) ;
while ( stream . Position < stream . Length )
{
OpenMetaverse . InventoryNode node = ( InventoryNode ) bformatter . Deserialize ( stream ) ;
nodes . Add ( node ) ;
item_count + + ;
}
2009-02-26 20:41:39 +00:00
}
}
catch ( Exception e )
{
Logger . Log ( "Error accessing inventory cache file :" + e . Message , Helpers . LogLevel . Error ) ;
2009-06-27 20:51:14 +00:00
return - 1 ;
2009-02-26 20:41:39 +00:00
}
Logger . Log ( "Read " + item_count . ToString ( ) + " items from inventory cache file" , Helpers . LogLevel . Info ) ;
item_count = 0 ;
2009-06-27 20:51:14 +00:00
List < InventoryNode > del_nodes = new List < InventoryNode > ( ) ; //nodes that we have processed and will delete
2010-03-14 12:50:01 +00:00
List < UUID > dirty_folders = new List < UUID > ( ) ; // Tainted folders that we will not restore items into
2009-02-26 20:41:39 +00:00
2009-06-27 20:51:14 +00:00
// Because we could get child nodes before parents we must itterate around and only add nodes who have
2009-02-26 20:41:39 +00:00
// a parent already in the list because we must update both child and parent to link together
2009-06-28 16:13:58 +00:00
// But sometimes we have seen orphin nodes due to bad/incomplete data when caching so we have an emergency abort route
2009-06-27 20:51:14 +00:00
int stuck = 0 ;
while ( nodes . Count ! = 0 & & stuck < 5 )
2009-02-26 20:41:39 +00:00
{
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 ) ;
2009-06-27 20:51:14 +00:00
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 )
{
2011-03-31 02:53:13 +00:00
Logger . DebugLog ( "Inventory Cache/Server version mismatch on " + node . Data . Name + " " + cache_folder . Version . ToString ( ) + " vs " + server_folder . Version . ToString ( ) ) ;
2009-06-28 16:13:58 +00:00
pnode . NeedsUpdate = true ;
2010-03-14 12:50:01 +00:00
dirty_folders . Add ( node . Data . UUID ) ;
2009-06-27 20:51:14 +00:00
}
2011-03-31 02:53:13 +00:00
else
{
pnode . NeedsUpdate = false ;
}
2009-06-27 20:51:14 +00:00
del_nodes . Add ( node ) ;
}
2009-02-26 20:41:39 +00:00
}
else if ( Items . TryGetValue ( node . ParentID , out pnode ) )
{
if ( node . Data ! = null )
{
2010-03-14 12:50:01 +00:00
// 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 ) ;
}
2009-02-26 20:41:39 +00:00
//Only add new items, this is most likely to be run at login time before any inventory
2010-03-14 12:50:01 +00:00
//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 ) )
2009-02-26 20:41:39 +00:00
{
2009-06-28 16:13:58 +00:00
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 + + ;
2009-02-26 20:41:39 +00:00
}
}
del_nodes . Add ( node ) ;
}
}
2009-06-27 20:51:14 +00:00
if ( del_nodes . Count = = 0 )
stuck + + ;
else
stuck = 0 ;
2009-02-26 20:41:39 +00:00
//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 ) ;
2009-06-27 20:51:14 +00:00
return item_count ;
2009-02-26 20:41:39 +00:00
}
2008-08-21 01:19:06 +00:00
#region Operators
2007-09-10 10:20:30 +00:00
/// <summary>
2008-08-21 01:19:06 +00:00
/// By using the bracket operator on this class, the program can get the
/// InventoryObject designated by the specified uuid. If the value for the corresponding
/// UUID is null, the call is equivelant to a call to <code>RemoveNodeFor(this[uuid])</code>.
/// If the value is non-null, it is equivelant to a call to <code>UpdateNodeFor(value)</code>,
/// the uuid parameter is ignored.
2007-09-10 10:20:30 +00:00
/// </summary>
2008-08-21 01:19:06 +00:00
/// <param name="uuid">The UUID of the InventoryObject to get or set, ignored if set to non-null value.</param>
/// <returns>The InventoryObject corresponding to <code>uuid</code>.</returns>
public InventoryBase this [ UUID uuid ]
2007-09-10 10:20:30 +00:00
{
get
{
2008-08-21 01:19:06 +00:00
InventoryNode node = Items [ uuid ] ;
return node . Data ;
2008-07-29 21:36:53 +00:00
}
2008-08-21 01:19:06 +00:00
set
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
if ( value ! = null )
2008-07-29 21:36:53 +00:00
{
2008-08-21 01:19:06 +00:00
// Log a warning if there is a UUID mismatch, this will cause problems
if ( value . UUID ! = uuid )
Logger . Log ( "Inventory[uuid]: uuid " + uuid . ToString ( ) + " is not equal to value.UUID " +
value . UUID . ToString ( ) , Helpers . LogLevel . Warning , Client ) ;
2008-07-29 21:36:53 +00:00
2008-08-21 01:19:06 +00:00
UpdateNodeFor ( value ) ;
}
else
2007-09-10 10:20:30 +00:00
{
2008-08-21 01:19:06 +00:00
InventoryNode node ;
if ( Items . TryGetValue ( uuid , out node ) )
2007-09-10 10:20:30 +00:00
{
2008-08-21 01:19:06 +00:00
RemoveNodeFor ( node . Data ) ;
2007-09-10 10:20:30 +00:00
}
}
}
}
2008-08-21 01:19:06 +00:00
#endregion Operators
2009-10-29 09:39:43 +00:00
}
#region EventArgs classes
public class InventoryObjectUpdatedEventArgs : EventArgs
{
private readonly InventoryBase m_OldObject ;
private readonly InventoryBase m_NewObject ;
2008-07-29 21:36:53 +00:00
2009-10-29 09:39:43 +00:00
public InventoryBase OldObject { get { return m_OldObject ; } }
public InventoryBase NewObject { get { return m_NewObject ; } }
2008-07-29 21:36:53 +00:00
2009-10-29 09:39:43 +00:00
public InventoryObjectUpdatedEventArgs ( InventoryBase oldObject , InventoryBase newObject )
2008-08-21 01:19:06 +00:00
{
2009-10-29 09:39:43 +00:00
this . m_OldObject = oldObject ;
this . m_NewObject = newObject ;
2007-07-13 14:49:36 +00:00
}
2009-10-29 09:39:43 +00:00
}
public class InventoryObjectRemovedEventArgs : EventArgs
{
private readonly InventoryBase m_Obj ;
2007-09-10 10:20:30 +00:00
2009-10-29 09:39:43 +00:00
public InventoryBase Obj { get { return m_Obj ; } }
public InventoryObjectRemovedEventArgs ( InventoryBase obj )
2008-07-29 21:36:53 +00:00
{
2009-10-29 09:39:43 +00:00
this . m_Obj = obj ;
2008-07-29 21:36:53 +00:00
}
2009-10-29 09:39:43 +00:00
}
2008-07-29 21:36:53 +00:00
2009-10-29 09:39:43 +00:00
public class InventoryObjectAddedEventArgs : EventArgs
{
private readonly InventoryBase m_Obj ;
public InventoryBase Obj { get { return m_Obj ; } }
public InventoryObjectAddedEventArgs ( InventoryBase obj )
2008-08-05 05:07:53 +00:00
{
2009-10-29 09:39:43 +00:00
this . m_Obj = obj ;
2008-03-31 21:31:02 +00:00
}
2007-07-13 14:49:36 +00:00
}
2009-10-29 09:39:43 +00:00
#endregion EventArgs
2007-07-13 14:49:36 +00:00
}