2006-10-21 02:52:28 +00:00
/ *
* Copyright ( c ) 2006 , Second Life Reverse Engineering Team
* 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 .
* - Neither the name of the Second Life Reverse Engineering Team nor the names
* 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 .
* /
2006-11-02 22:28:46 +00:00
//#define DEBUG_PACKETS
2006-10-21 02:52:28 +00:00
using System ;
2006-12-19 23:13:04 +00:00
using System.Collections ;
2006-10-21 05:53:58 +00:00
using System.Collections.Generic ;
2007-03-01 00:26:47 +00:00
using System.Text ;
2006-11-02 22:28:46 +00:00
using System.Threading ;
2006-10-21 02:52:28 +00:00
using libsecondlife ;
using libsecondlife.AssetSystem ;
using libsecondlife.Packets ;
namespace libsecondlife.InventorySystem
{
2006-10-21 05:53:58 +00:00
/// <summary>
/// Summary description for Inventory.
/// </summary>
public class InventoryManager
{
2006-10-21 02:52:28 +00:00
2006-10-21 05:53:58 +00:00
// Reference to the SLClient Library
private SecondLife slClient ;
2007-03-11 06:17:24 +00:00
// private ManualResetEvent InventoryManagerInitialized = new ManualResetEvent(false);
2006-10-21 02:52:28 +00:00
2006-10-21 05:53:58 +00:00
// Reference to the Asset Manager
2007-07-14 00:27:23 +00:00
internal libsecondlife . AssetManager AssetManager
2006-10-21 05:53:58 +00:00
{
2007-01-05 22:38:15 +00:00
get { return slClient . Assets ; }
2006-10-21 05:53:58 +00:00
}
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
// Packet assembly helper
2006-10-21 02:52:28 +00:00
public InventoryPacketHelper InvPacketHelper = null ;
2006-10-25 10:41:43 +00:00
// Setup a dictionary to easily lookup folders by UUID
2007-01-05 22:38:15 +00:00
private Dictionary < LLUUID , InventoryFolder > FoldersByUUID = new Dictionary < LLUUID , InventoryFolder > ( ) ;
2006-10-21 02:52:28 +00:00
2006-10-25 10:41:43 +00:00
// Setup a dictionary to track download progress
2007-02-24 00:17:42 +00:00
// protected Dictionary<LLUUID, DownloadRequest_Folder> FolderDownloadStatus = new Dictionary<LLUUID, DownloadRequest_Folder>();
protected List < DownloadRequest_Folder > FolderRequests = new List < DownloadRequest_Folder > ( ) ;
protected bool CurrentlyDownloadingAFolder = false ;
protected DownloadRequest_Folder CurrentlyDownloadingRequest = null ;
private Mutex CurrentlyDownloadingMutex = new Mutex ( ) ;
2006-10-21 02:52:28 +00:00
2007-02-21 21:37:37 +00:00
protected Dictionary < sbyte , InventoryFolder > FolderByType = new Dictionary < sbyte , InventoryFolder > ( ) ;
2006-10-21 02:52:28 +00:00
// Used to track current item being created
private InventoryItem iiCreationInProgress ;
2006-11-02 22:28:46 +00:00
public ManualResetEvent ItemCreationCompleted ;
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
// Used to track to see if a download has timed out or not
2007-03-11 06:17:24 +00:00
// private int LastPacketRecievedAtTick;
2006-10-21 02:52:28 +00:00
2007-02-23 21:59:56 +00:00
public enum InventoryType : sbyte
{
Unknown = - 1 ,
Texture = 0 ,
Sound = 1 ,
CallingCard = 2 ,
Landmark = 3 ,
[Obsolete]
Script = 4 ,
[Obsolete]
Clothing = 5 ,
Object = 6 ,
Notecard = 7 ,
Category = 8 ,
2007-02-24 00:17:42 +00:00
Folder = 8 ,
2007-02-23 21:59:56 +00:00
RootCategory = 0 ,
LSL = 10 ,
[Obsolete]
LSLBytecode = 11 ,
[Obsolete]
TextureTGA = 12 ,
[Obsolete]
Bodypart = 13 ,
[Obsolete]
Trash = 14 ,
Snapshot = 15 ,
[Obsolete]
LostAndFound = 16 ,
Attachment = 17 ,
Wearable = 18 ,
Animation = 19 ,
Gesture = 20
}
2007-03-01 00:26:47 +00:00
/// <summary>
/// Used to turn on debug logging of descendant downloading.
/// </summary>
public bool LogDescendantQueue = false ;
2007-01-05 02:32:21 +00:00
/// <summary>
/// Download event singalling that folder contents have been downloaded.
/// </summary>
/// <param name="InventoryFolder">The Inventory Folder that was updated</param>
/// <param name="e"></param>
2007-01-05 18:23:19 +00:00
public delegate void On_RequestDownloadContents_Finished ( object iFolder , EventArgs e ) ;
2007-01-23 01:22:58 +00:00
public event On_RequestDownloadContents_Finished OnRequestDownloadFinishedEvent ;
public delegate void On_InventoryItemReceived ( LLUUID fromAgentID , string fromAgentName , uint parentEstateID , LLUUID regionID , LLVector3 position , DateTime timestamp , InventoryItem item ) ;
public event On_InventoryItemReceived OnInventoryItemReceived ;
2007-01-05 02:32:21 +00:00
2007-02-24 00:17:42 +00:00
public delegate void On_InventoryFolderReceived ( LLUUID fromAgentID , string fromAgentName , uint parentEstateID , LLUUID regionID , LLVector3 position , DateTime timestamp , InventoryFolder folder ) ;
public event On_InventoryFolderReceived OnInventoryFolderReceived ;
2007-01-05 22:38:15 +00:00
/// <summary>
/// Primary constructor
/// </summary>
/// <param name="client"></param>
2006-12-19 23:13:04 +00:00
public InventoryManager ( SecondLife client )
2006-10-21 05:53:58 +00:00
{
slClient = client ;
2006-10-21 02:52:28 +00:00
2006-12-19 23:13:04 +00:00
InvPacketHelper = new InventoryPacketHelper ( slClient ) ;
2006-10-21 05:53:58 +00:00
2006-12-19 23:13:04 +00:00
// Need to know what when we're connected/disconnected
slClient . Network . OnConnected + = new NetworkManager . ConnectedCallback ( Network_OnConnected ) ;
2007-02-22 18:13:42 +00:00
slClient . Network . OnDisconnected + = new NetworkManager . DisconnectedCallback ( Network_OnDisconnected ) ;
2006-10-21 05:53:58 +00:00
// Setup the callback for Inventory Downloads
2006-11-09 10:18:03 +00:00
slClient . Network . RegisterCallback ( PacketType . InventoryDescendents , new NetworkManager . PacketCallback ( InventoryDescendentsHandler ) ) ;
2006-10-21 02:52:28 +00:00
// Setup the callback for Inventory Creation Update
2006-11-09 10:18:03 +00:00
slClient . Network . RegisterCallback ( PacketType . UpdateCreateInventoryItem , new NetworkManager . PacketCallback ( UpdateCreateInventoryItemHandler ) ) ;
2006-10-21 05:53:58 +00:00
2007-01-23 01:22:58 +00:00
// Lets listen for inventory being given to us
slClient . Self . OnInstantMessage + = new MainAvatar . InstantMessageCallback ( Self_OnInstantMessage ) ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
#region State Management
/// <summary>
/// Inventory Management state should be cleared on connect/disconnect.
/// </summary>
/// <param name="reason"></param>
/// <param name="message"></param>
2006-12-19 23:13:04 +00:00
void Network_OnDisconnected ( NetworkManager . DisconnectType reason , string message )
2006-10-21 05:53:58 +00:00
{
2006-12-19 23:13:04 +00:00
// Clear out current state
ClearState ( ) ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Inventory Management state should be cleared on connect/disconnect.
/// </summary>
/// <param name="sender"></param>
2006-12-19 23:13:04 +00:00
void Network_OnConnected ( object sender )
2006-10-21 05:53:58 +00:00
{
2006-12-19 23:13:04 +00:00
// Clear out current state
ClearState ( ) ;
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Reset the current state of the InventorySystem
/// </summary>
2006-12-19 23:13:04 +00:00
private void ClearState ( )
{
2007-01-05 22:38:15 +00:00
FoldersByUUID . Clear ( ) ;
2007-02-22 23:59:39 +00:00
2007-02-24 00:17:42 +00:00
lock ( FolderRequests )
2007-02-22 23:59:39 +00:00
{
2007-02-24 00:17:42 +00:00
FolderRequests . Clear ( ) ;
2007-02-22 23:59:39 +00:00
}
2006-12-19 23:13:04 +00:00
if ( slClient . Self . InventoryRootFolderUUID ! = null )
{
// Init folder structure with root
InventoryFolder ifRootFolder = new InventoryFolder ( this , "My Inventory" , slClient . Self . InventoryRootFolderUUID , null ) ;
2007-01-05 22:38:15 +00:00
FoldersByUUID [ slClient . Self . InventoryRootFolderUUID ] = ifRootFolder ;
2006-12-19 23:13:04 +00:00
}
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
#endregion
2006-10-21 05:53:58 +00:00
2007-01-05 22:38:15 +00:00
#region Folder Navigation
/// <summary>
/// Get the root folder of a client's inventory
/// </summary>
/// <returns></returns>
2006-12-29 17:59:48 +00:00
public InventoryFolder GetRootFolder ( )
2006-10-21 05:53:58 +00:00
{
2007-01-05 22:38:15 +00:00
return FoldersByUUID [ slClient . Self . InventoryRootFolderUUID ] ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Get a specific folder by FolderID from the local cached inventory information
/// </summary>
/// <param name="folderID"></param>
/// <returns>Returns null if the folder doesn't exist in cached inventory</returns>
2006-10-21 05:53:58 +00:00
public InventoryFolder getFolder ( LLUUID folderID )
{
2007-01-05 22:38:15 +00:00
if ( FoldersByUUID . ContainsKey ( folderID ) )
{
return FoldersByUUID [ folderID ] ;
}
else
{
return null ;
}
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Get a specific folder by Name from the local cached inventory information
/// </summary>
/// <param name="sFolderPath"></param>
/// <returns></returns>
2006-10-21 05:53:58 +00:00
public InventoryFolder getFolder ( String sFolderPath )
{
string sSecretConst = "+@#%$#$%^%^%$^$%SV$#%FR$G" ;
sFolderPath = sFolderPath . Replace ( "//" , sSecretConst ) ;
2006-10-21 02:52:28 +00:00
if ( sFolderPath . StartsWith ( "/" ) )
{
sFolderPath = sFolderPath . Remove ( 0 , 1 ) ;
}
if ( sFolderPath . Length = = 0 )
{
2006-12-29 17:59:48 +00:00
return GetRootFolder ( ) ;
2006-10-21 02:52:28 +00:00
}
char [ ] seperators = { '/' } ;
2006-10-21 05:53:58 +00:00
string [ ] sFolderPathParts = sFolderPath . Split ( seperators ) ;
2006-10-21 02:52:28 +00:00
2006-10-21 05:53:58 +00:00
for ( int i = 0 ; i < sFolderPathParts . Length ; i + + )
{
sFolderPathParts [ i ] = sFolderPathParts [ i ] . Replace ( sSecretConst , "/" ) ;
}
2006-10-21 02:52:28 +00:00
2006-10-21 05:53:58 +00:00
Queue < string > pathParts = new Queue < string > ( sFolderPathParts ) ;
2006-10-21 02:52:28 +00:00
return getFolder ( pathParts ) ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Recursive helper function for public InventoryFolder getFolder(String sFolderPath)
/// </summary>
2007-01-25 14:04:23 +00:00
/// <param name="qFolderPath">Queue</param>
2007-01-05 22:38:15 +00:00
/// <returns></returns>
2006-10-21 05:53:58 +00:00
private InventoryFolder getFolder ( Queue < string > qFolderPath )
{
2006-12-29 17:59:48 +00:00
return getFolder ( qFolderPath , GetRootFolder ( ) ) ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Recursive helper function for public InventoryFolder getFolder(String sFolderPath)
/// </summary>
/// <param name="qFolderPath"></param>
/// <param name="ifRoot"></param>
/// <returns></returns>
2006-10-21 05:53:58 +00:00
private InventoryFolder getFolder ( Queue < string > qFolderPath , InventoryFolder ifRoot )
{
string sCurFolder = qFolderPath . Dequeue ( ) ;
2006-12-19 23:13:04 +00:00
foreach ( InventoryBase ibFolder in ifRoot . _Contents )
2006-10-21 05:53:58 +00:00
{
if ( ibFolder is libsecondlife . InventorySystem . InventoryFolder )
{
if ( ( ( InventoryFolder ) ibFolder ) . Name . Equals ( sCurFolder ) )
{
if ( qFolderPath . Count = = 0 )
{
return ( InventoryFolder ) ibFolder ;
}
else
{
return getFolder ( qFolderPath , ( InventoryFolder ) ibFolder ) ;
}
}
}
}
2007-01-14 05:27:40 +00:00
// Try updating the current level's child folders, then look again
2007-02-24 00:17:42 +00:00
if ( ifRoot . RequestDownloadContents ( false , true , false ) . RequestComplete . WaitOne ( 1000 , false ) )
2007-01-14 05:27:40 +00:00
{
foreach ( InventoryBase ibFolder in ifRoot . _Contents )
{
if ( ibFolder is libsecondlife . InventorySystem . InventoryFolder )
{
if ( ( ( InventoryFolder ) ibFolder ) . Name . Equals ( sCurFolder ) )
{
// NOTE: We only found it because we did a folder download,
// perhaps we should initiate a recursive download at this point
if ( qFolderPath . Count = = 0 )
{
return ( InventoryFolder ) ibFolder ;
}
else
{
return getFolder ( qFolderPath , ( InventoryFolder ) ibFolder ) ;
}
}
}
}
}
2006-10-21 05:53:58 +00:00
return null ;
}
2007-01-05 22:38:15 +00:00
#endregion
#region Inventory Creation Functions
2006-10-21 05:53:58 +00:00
2006-12-19 23:13:04 +00:00
/// <summary>
2007-02-21 21:37:37 +00:00
/// Request that a folder be created
2006-12-19 23:13:04 +00:00
/// </summary>
2007-01-09 07:19:44 +00:00
/// <param name="name"></param>
/// <param name="parentid"></param>
2007-02-21 21:37:37 +00:00
internal LLUUID FolderCreate ( String name , LLUUID parentid )
2006-10-21 05:53:58 +00:00
{
2007-02-21 21:37:37 +00:00
LLUUID requestedFolderID = LLUUID . Random ( ) ;
InventoryFolder ifolder = new InventoryFolder ( this , name , requestedFolderID , parentid ) ;
2006-10-21 05:53:58 +00:00
ifolder . _Type = - 1 ;
2007-01-05 22:38:15 +00:00
if ( FoldersByUUID . ContainsKey ( ifolder . ParentID ) )
2006-10-21 05:53:58 +00:00
{
2007-01-05 22:38:15 +00:00
if ( ( ( InventoryFolder ) FoldersByUUID [ ifolder . ParentID ] ) . _Contents . Contains ( ifolder ) = = false )
2006-10-21 05:53:58 +00:00
{
// Add new folder to the contents of the parent folder.
2007-01-05 22:38:15 +00:00
( ( InventoryFolder ) FoldersByUUID [ ifolder . ParentID ] ) . _Contents . Add ( ifolder ) ;
2006-10-21 05:53:58 +00:00
}
}
else
{
throw new Exception ( "Parent Folder " + ifolder . ParentID + " does not exist in this Inventory Manager." ) ;
}
2007-01-05 22:38:15 +00:00
if ( FoldersByUUID . ContainsKey ( ifolder . FolderID ) = = false )
2006-10-21 05:53:58 +00:00
{
2007-01-05 22:38:15 +00:00
FoldersByUUID [ ifolder . FolderID ] = ifolder ;
2006-10-21 05:53:58 +00:00
}
2006-10-21 02:52:28 +00:00
Packet packet = InvPacketHelper . CreateInventoryFolder ( ifolder . Name , ifolder . ParentID , ifolder . Type , ifolder . FolderID ) ;
2006-10-21 05:53:58 +00:00
slClient . Network . SendPacket ( packet ) ;
2007-02-21 21:37:37 +00:00
return requestedFolderID ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Create a new notecard
/// </summary>
/// <param name="Name"></param>
/// <param name="Description"></param>
/// <param name="Body"></param>
/// <param name="FolderID"></param>
/// <returns></returns>
internal InventoryNotecard NewNotecard ( string Name , string Description , string Body , LLUUID FolderID )
{
InventoryNotecard iNotecard = new InventoryNotecard ( this , Name , Description , FolderID , slClient . Network . AgentID ) ;
2006-10-21 05:53:58 +00:00
2007-01-05 22:38:15 +00:00
// Create this notecard on the server.
ItemCreate ( iNotecard ) ;
if ( ( Body ! = null ) & & ( Body . Equals ( "" ) ! = true ) )
{
iNotecard . Body = Body ;
}
return iNotecard ;
}
2007-05-07 04:52:36 +00:00
internal InventoryLandmark NewLandmark ( string Name , string Description , LLUUID FolderID )
{
InventoryLandmark iLandmark = new InventoryLandmark ( this , Name , Description , FolderID , slClient . Network . AgentID ) ;
// Create this notecard on the server.
ItemCreate ( iLandmark ) ;
return iLandmark ;
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Create a new image
/// </summary>
/// <param name="Name"></param>
/// <param name="Description"></param>
/// <param name="j2cdata"></param>
/// <param name="FolderID"></param>
/// <returns></returns>
internal InventoryImage NewImage ( string Name , string Description , byte [ ] j2cdata , LLUUID FolderID )
{
InventoryImage iImage = new InventoryImage ( this , Name , Description , FolderID , slClient . Network . AgentID ) ;
// Create this image on the server.
ItemCreate ( iImage ) ;
if ( ( j2cdata ! = null ) & & ( j2cdata . Length ! = 0 ) )
{
iImage . J2CData = j2cdata ;
}
return iImage ;
}
#endregion
#region Folder Management
/// <summary>
/// Flushes the local cache of this folder's contents
/// </summary>
/// <param name="iFolder"></param>
/// <param name="Folders">Clear Folders</param>
/// <param name="Items">Clear Items</param>
2007-02-24 00:17:42 +00:00
public void FolderClearContents ( InventoryFolder iFolder , bool Folders , bool Items )
2007-01-05 22:38:15 +00:00
{
// Need to recursively do this...
while ( iFolder . _Contents . Count > 0 )
{
InventoryBase ib = iFolder . _Contents [ 0 ] ;
if ( ( ib is InventoryFolder ) & & Folders )
{
InventoryFolder ChildFolder = ( InventoryFolder ) ib ;
FolderClearContents ( ChildFolder , Folders , Items ) ;
if ( FoldersByUUID . ContainsKey ( ChildFolder . FolderID ) )
{
FoldersByUUID . Remove ( ChildFolder . FolderID ) ;
}
iFolder . _Contents . Remove ( ib ) ;
}
else if ( Items )
{
iFolder . _Contents . Remove ( ib ) ;
}
}
}
/// <summary>
/// Delete/Remove a folder
/// </summary>
/// <param name="ifolder"></param>
2006-10-21 05:53:58 +00:00
internal void FolderRemove ( InventoryFolder ifolder )
{
2007-01-05 22:38:15 +00:00
// Need to recursively remove children
foreach ( InventoryBase ib in ifolder . GetContents ( ) )
{
if ( ib is InventoryFolder )
{
InventoryFolder ifChild = ( InventoryFolder ) ib ;
FolderRemove ( ifChild ) ;
}
}
// Remove from parent
if ( FoldersByUUID . ContainsKey ( ifolder . ParentID ) )
{
InventoryFolder ifParent = FoldersByUUID [ ifolder . ParentID ] ;
if ( ifParent . _Contents . Contains ( ifolder ) )
{
ifParent . _Contents . Remove ( ifolder ) ;
}
}
// Remove from lookup cache
if ( FoldersByUUID . ContainsKey ( ifolder . FolderID ) )
{
FoldersByUUID . Remove ( ifolder . FolderID ) ;
}
Packet packet = InvPacketHelper . RemoveInventoryFolder ( ifolder . FolderID ) ;
slClient . Network . SendPacket ( packet ) ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Delete/Remove a folder
/// </summary>
/// <param name="folderID"></param>
2006-10-21 05:53:58 +00:00
internal void FolderRemove ( LLUUID folderID )
{
2007-01-05 22:38:15 +00:00
if ( FoldersByUUID . ContainsKey ( folderID ) )
{
FolderRemove ( FoldersByUUID [ folderID ] ) ;
}
2006-10-21 05:53:58 +00:00
}
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
/// <summary>
/// Move a folder
/// </summary>
/// <param name="iFolder"></param>
/// <param name="newParentID"></param>
2006-10-21 05:53:58 +00:00
internal void FolderMove ( InventoryFolder iFolder , LLUUID newParentID )
{
2007-01-05 22:38:15 +00:00
//Remove this folder from the old parent
if ( FoldersByUUID . ContainsKey ( iFolder . ParentID ) )
{
InventoryFolder ParentFolder = FoldersByUUID [ iFolder . ParentID ] ;
if ( ParentFolder . _Contents . Contains ( iFolder ) )
{
ParentFolder . _Contents . Remove ( iFolder ) ;
}
}
// Set Parent ID
iFolder . _ParentID = newParentID ;
// Add to Parent's contents
if ( FoldersByUUID . ContainsKey ( iFolder . ParentID ) )
{
InventoryFolder ParentFolder = FoldersByUUID [ iFolder . ParentID ] ;
if ( ! ParentFolder . _Contents . Contains ( iFolder ) )
{
ParentFolder . _Contents . Add ( iFolder ) ;
}
}
2006-10-21 02:52:28 +00:00
Packet packet = InvPacketHelper . MoveInventoryFolder ( newParentID , iFolder . FolderID ) ;
2006-10-21 05:53:58 +00:00
slClient . Network . SendPacket ( packet ) ;
}
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
/// <summary>
/// Rename a folder
/// </summary>
/// <param name="ifolder"></param>
2006-10-21 05:53:58 +00:00
internal void FolderRename ( InventoryFolder ifolder )
{
2006-10-21 02:52:28 +00:00
Packet packet = InvPacketHelper . UpdateInventoryFolder ( ifolder . Name , ifolder . ParentID , ifolder . Type , ifolder . FolderID ) ;
2006-10-21 05:53:58 +00:00
slClient . Network . SendPacket ( packet ) ;
}
2007-01-05 22:38:15 +00:00
#endregion
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
#region Item Management
/// <summary>
/// Create a new inventory item
/// </summary>
/// <param name="iitem"></param>
2006-10-21 02:52:28 +00:00
internal void ItemCreate ( InventoryItem iitem )
{
2006-11-02 22:28:46 +00:00
if ( iiCreationInProgress ! = null )
2006-10-21 02:52:28 +00:00
{
throw new Exception ( "Can only create one item at a time, and an item creation is already in progress." ) ;
}
2006-11-02 22:28:46 +00:00
2006-11-05 21:05:25 +00:00
try
{
ItemCreationCompleted = new ManualResetEvent ( false ) ;
iiCreationInProgress = iitem ;
2006-10-21 02:52:28 +00:00
2006-11-05 21:05:25 +00:00
Packet packet = InvPacketHelper . CreateInventoryItem ( iitem ) ;
2006-11-08 14:40:55 +00:00
int i = 0 ;
do
{
if ( i + + > 10 )
throw new Exception ( "Could not create " + iitem . Name ) ;
slClient . Network . SendPacket ( packet ) ;
2006-11-02 22:28:46 +00:00
2006-11-05 21:05:25 +00:00
#if DEBUG_PACKETS
2006-12-20 23:50:35 +00:00
slClient . DebugLog ( packet ) ;
2006-11-05 21:05:25 +00:00
#endif
2006-11-08 14:40:55 +00:00
} while ( ! ItemCreationCompleted . WaitOne ( 5000 , false ) ) ;
2006-11-05 21:05:25 +00:00
}
finally
{
iiCreationInProgress = null ;
}
2006-10-21 02:52:28 +00:00
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Update an existing item
/// </summary>
/// <param name="iitem"></param>
2006-10-21 05:53:58 +00:00
internal void ItemUpdate ( InventoryItem iitem )
{
2006-10-21 02:52:28 +00:00
Packet packet = InvPacketHelper . UpdateInventoryItem ( iitem ) ;
2006-10-21 05:53:58 +00:00
slClient . Network . SendPacket ( packet ) ;
2006-11-02 22:28:46 +00:00
#if DEBUG_PACKETS
2006-12-20 23:50:35 +00:00
slClient . DebugLog ( packet ) ;
2006-11-02 22:28:46 +00:00
#endif
2006-10-21 05:53:58 +00:00
}
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
/// <summary>
/// Copy an item
/// </summary>
/// <param name="ItemID"></param>
/// <param name="TargetFolderID"></param>
2006-10-21 05:53:58 +00:00
internal void ItemCopy ( LLUUID ItemID , LLUUID TargetFolderID )
{
2006-10-21 02:52:28 +00:00
Packet packet = InvPacketHelper . CopyInventoryItem ( ItemID , TargetFolderID ) ;
2006-10-21 05:53:58 +00:00
slClient . Network . SendPacket ( packet ) ;
2006-11-02 22:28:46 +00:00
#if DEBUG_PACKETS
2006-12-20 23:50:35 +00:00
slClient . DebugLog ( packet ) ;
2006-11-02 22:28:46 +00:00
#endif
2006-10-21 05:53:58 +00:00
}
2006-10-21 02:52:28 +00:00
2007-02-28 02:19:35 +00:00
internal void MoveItem ( LLUUID itemID , LLUUID targetFolderID )
{
Packet packet = InvPacketHelper . MoveInventoryItem ( itemID , targetFolderID ) ;
slClient . Network . SendPacket ( packet ) ;
#if DEBUG_PACKETS
slClient . Log ( packet . ToString ( ) , Helpers . LogLevel . Info ) ;
#endif
}
2007-01-05 22:38:15 +00:00
/// <summary>
/// Give an item to someone
/// </summary>
/// <param name="iitem"></param>
/// <param name="ToAgentID"></param>
2006-10-21 05:53:58 +00:00
internal void ItemGiveTo ( InventoryItem iitem , LLUUID ToAgentID )
{
2006-12-04 00:19:58 +00:00
LLUUID MessageID = LLUUID . Random ( ) ;
2006-10-21 02:52:28 +00:00
2006-11-09 19:14:11 +00:00
Packet packet = InvPacketHelper . GiveItemViaImprovedInstantMessage (
2006-10-21 05:53:58 +00:00
MessageID
, ToAgentID
2006-10-24 11:16:26 +00:00
, slClient . Self . FirstName + " " + slClient . Self . LastName
, slClient . Self . Position
2006-10-21 05:53:58 +00:00
, iitem
) ;
2006-10-21 02:52:28 +00:00
2006-10-21 05:53:58 +00:00
slClient . Network . SendPacket ( packet ) ;
2006-10-21 02:52:28 +00:00
2006-11-02 22:28:46 +00:00
#if DEBUG_PACKETS
2006-12-20 23:50:35 +00:00
slClient . DebugLog ( packet ) ;
2006-11-02 22:28:46 +00:00
#endif
2006-10-21 05:53:58 +00:00
}
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
/// <summary>
/// Remove/Delete an item
/// </summary>
/// <param name="iitem"></param>
2006-10-21 05:53:58 +00:00
internal void ItemRemove ( InventoryItem iitem )
{
InventoryFolder ifolder = getFolder ( iitem . FolderID ) ;
2006-12-19 23:13:04 +00:00
ifolder . _Contents . Remove ( iitem ) ;
2006-10-21 02:52:28 +00:00
Packet packet = InvPacketHelper . RemoveInventoryItem ( iitem . ItemID ) ;
2006-10-21 05:53:58 +00:00
slClient . Network . SendPacket ( packet ) ;
2006-11-02 22:28:46 +00:00
#if DEBUG_PACKETS
2006-12-20 23:50:35 +00:00
slClient . DebugLog ( packet ) ;
2006-11-02 22:28:46 +00:00
#endif
2006-10-21 05:53:58 +00:00
}
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
#endregion
2006-10-21 02:52:28 +00:00
2007-01-05 22:38:15 +00:00
#region Misc
2007-01-06 00:13:39 +00:00
2007-01-11 17:53:55 +00:00
/// <summary>
/// Rez the given item into the given sim.
/// </summary>
/// <param name="item"></param>
/// <param name="TargetSim">You can specify null to use the current sim</param>
/// <param name="TargetPos">Position is in Region coordinates</param>
2007-01-06 00:13:39 +00:00
internal void ItemRezObject ( InventoryItem item , Simulator TargetSim , LLVector3 TargetPos )
{
Packet packet = InvPacketHelper . RezObject ( item , TargetPos ) ;
if ( TargetSim = = null )
{
slClient . Network . SendPacket ( packet ) ;
}
else
{
slClient . Network . SendPacket ( packet , TargetSim ) ;
}
}
2007-01-11 20:44:16 +00:00
/// <summary>
/// Attempt to rez and attach an inventory item
/// </summary>
/// <param name="Item"></param>
/// <param name="AttachmentPt"></param>
internal void ItemRezAttach ( InventoryItem Item , ObjectManager . AttachmentPoint AttachmentPt )
{
Packet p = InvPacketHelper . RezSingleAttachmentFromInv ( Item , AttachmentPt ) ;
slClient . Network . SendPacket ( p ) ;
}
/// <summary>
/// Attempt to detach and return an item to your inventory
/// </summary>
/// <param name="Item"></param>
internal void ItemDetach ( InventoryItem Item )
{
Packet p = InvPacketHelper . DetachAttachmentIntoInv ( Item . ItemID ) ;
slClient . Network . SendPacket ( p ) ;
}
2007-03-01 00:26:47 +00:00
#endregion
#region Folder Downloading
protected void LogDescendantQueueEvent ( string msg )
{
if ( LogDescendantQueue )
{
StringBuilder sb = new StringBuilder ( ) ;
sb . AppendLine ( "==============================" ) ;
sb . AppendLine ( msg ) ;
if ( CurrentlyDownloadingRequest = = null )
{
sb . AppendLine ( "CurrentlyDownloadingRequest: NULL" ) ;
}
else
{
sb . AppendLine ( "CurrentlyDownloadingRequest: " + CurrentlyDownloadingRequest . ToString ( ) ) ;
}
sb . AppendLine ( "Current queue status:" ) ;
lock ( FolderRequests )
{
if ( FolderRequests . Count = = 0 )
{
sb . AppendLine ( " *** Download Queue Empty ***" ) ;
}
else
{
foreach ( DownloadRequest_Folder dr in FolderRequests )
{
sb . AppendLine ( " * " + dr . ToString ( ) ) ;
}
}
}
slClient . Log ( sb . ToString ( ) , Helpers . LogLevel . Info ) ;
}
}
2007-01-11 20:44:16 +00:00
2007-01-05 22:38:15 +00:00
/// <summary>
2007-02-24 00:17:42 +00:00
/// Append a request to the end of the queue.
2007-01-05 22:38:15 +00:00
/// </summary>
2007-03-05 23:00:03 +00:00
internal DownloadRequest_Folder FolderRequestAppend ( LLUUID folderID , bool recurse , bool fetchFolders , bool fetchItems , string requestName )
2006-10-21 05:53:58 +00:00
{
2007-03-05 23:00:03 +00:00
DownloadRequest_Folder dr = new DownloadRequest_Folder ( folderID , recurse , fetchFolders , fetchItems , requestName ) ;
2007-03-01 00:26:47 +00:00
// Add new request to the tail of the queue
2007-02-24 00:17:42 +00:00
lock ( FolderRequests )
2007-02-22 00:09:45 +00:00
{
2007-03-05 23:00:03 +00:00
if ( FolderRequests . Contains ( dr ) )
{
foreach ( DownloadRequest_Folder existing in FolderRequests )
{
if ( dr . Equals ( existing ) )
{
dr = existing ;
break ;
}
}
LogDescendantQueueEvent ( "Append(returned existing): " + dr . ToString ( ) ) ;
}
else
{
FolderRequests . Add ( dr ) ;
LogDescendantQueueEvent ( "Append: " + dr . ToString ( ) ) ;
}
2007-02-22 00:09:45 +00:00
}
2007-01-11 18:04:18 +00:00
2007-02-24 00:17:42 +00:00
FolderRequestBegin ( ) ;
2007-03-05 23:00:03 +00:00
return dr ;
2007-02-24 00:17:42 +00:00
}
2006-10-21 02:52:28 +00:00
2007-03-05 23:00:03 +00:00
protected DownloadRequest_Folder FolderRequestPrepend ( LLUUID folderID , bool recurse , bool fetchFolders , bool fetchItems , string requestName )
2007-03-01 00:26:47 +00:00
{
2007-03-05 23:00:03 +00:00
DownloadRequest_Folder dr = new DownloadRequest_Folder ( folderID , recurse , fetchFolders , fetchItems , requestName ) ;
2007-03-01 00:26:47 +00:00
// Prepend the request at the head of the queue
lock ( FolderRequests )
{
2007-03-05 23:00:03 +00:00
if ( FolderRequests . Contains ( dr ) )
{
foreach ( DownloadRequest_Folder existing in FolderRequests )
{
if ( dr . Equals ( existing ) )
{
dr = existing ;
break ;
}
}
LogDescendantQueueEvent ( "Append(returned existing): " + dr . ToString ( ) ) ;
}
else
{
FolderRequests . Insert ( 0 , dr ) ;
LogDescendantQueueEvent ( "Prepend: " + dr . ToString ( ) ) ;
}
2007-03-01 00:26:47 +00:00
}
2007-03-05 23:00:03 +00:00
return dr ;
2007-03-01 00:26:47 +00:00
}
2007-02-24 00:17:42 +00:00
/// <summary>
/// If not currently downloading a request, dequeue the next request and start it.
/// </summary>
2007-03-01 00:26:47 +00:00
protected void FolderRequestBegin ( )
2007-02-24 00:17:42 +00:00
{
// 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 )
{
2007-03-01 00:26:47 +00:00
// Start downloading the first thing at the head of the queue
2007-02-24 00:17:42 +00:00
lock ( FolderRequests )
{
2007-03-01 00:26:47 +00:00
while ( ( FolderRequests . Count > 0 ) & & ( FolderRequests [ 0 ] . IsCompleted ) )
{
LogDescendantQueueEvent ( "Head request completed, notify recurse completed: " + FolderRequests [ 0 ] ) ;
FolderRequests . RemoveAt ( 0 ) ;
}
2007-02-24 00:17:42 +00:00
if ( FolderRequests . Count > 0 )
{
CurrentlyDownloadingRequest = FolderRequests [ 0 ] ;
2007-03-01 00:26:47 +00:00
LogDescendantQueueEvent ( "Starting download of head of queue: " + FolderRequests [ 0 ] . ToString ( ) ) ;
2007-02-24 00:17:42 +00:00
}
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 ( ) ;
2006-10-21 05:53:58 +00:00
}
2007-02-22 23:59:39 +00:00
/// <summary>
/// Issue a RequestDownload Finished event. Happens after each download request completes.
/// </summary>
/// <param name="o"></param>
/// <param name="e"></param>
2007-01-13 00:23:00 +00:00
protected void FireRequestDownloadFinishedEvent ( object o , EventArgs e )
{
2007-01-23 01:22:58 +00:00
if ( OnRequestDownloadFinishedEvent ! = null )
2007-01-14 05:27:40 +00:00
{
2007-01-23 01:22:58 +00:00
OnRequestDownloadFinishedEvent ( o , e ) ;
2007-01-14 05:27:40 +00:00
}
2007-01-13 00:23:00 +00:00
}
2007-01-05 22:38:15 +00:00
#endregion
2007-01-05 02:32:21 +00:00
#region libsecondlife callback handlers
2007-01-05 22:38:15 +00:00
2007-02-22 23:59:39 +00:00
/// <summary>
/// Used to track when inventory is dropped onto/into agent
/// </summary>
/// <param name="fromAgentID"></param>
/// <param name="fromAgentName"></param>
/// <param name="toAgentID"></param>
/// <param name="parentEstateID"></param>
/// <param name="regionID"></param>
/// <param name="position"></param>
/// <param name="dialog"></param>
/// <param name="groupIM"></param>
/// <param name="imSessionID"></param>
/// <param name="timestamp"></param>
/// <param name="message"></param>
/// <param name="offline"></param>
/// <param name="binaryBucket"></param>
2007-02-17 01:41:12 +00:00
void Self_OnInstantMessage ( LLUUID fromAgentID , string fromAgentName , LLUUID toAgentID , uint parentEstateID ,
LLUUID regionID , LLVector3 position , MainAvatar . InstantMessageDialog dialog , bool groupIM ,
LLUUID imSessionID , DateTime timestamp , string message , MainAvatar . InstantMessageOnline offline ,
byte [ ] binaryBucket )
2007-01-23 01:22:58 +00:00
{
2007-02-24 00:17:42 +00:00
if ( ( dialog = = MainAvatar . InstantMessageDialog . InventoryOffered ) & & ( ( OnInventoryItemReceived ! = null ) | | ( OnInventoryFolderReceived ! = null ) ) )
2007-01-23 01:22:58 +00:00
{
sbyte IncomingItemType = ( sbyte ) binaryBucket [ 0 ] ;
2007-02-24 00:17:42 +00:00
LLUUID IncomingUUID = new LLUUID ( binaryBucket , 1 ) ;
2007-01-23 01:22:58 +00:00
// Update root folders
InventoryFolder root = GetRootFolder ( ) ;
if ( root . GetContents ( ) . Count = = 0 )
{
2007-02-24 00:17:42 +00:00
root . RequestDownloadContents ( false , true , false ) . RequestComplete . WaitOne ( 3000 , false ) ;
}
// Handle the case of the incoming inventory folder
if ( IncomingItemType = = ( sbyte ) InventoryManager . InventoryType . Folder )
{
2007-03-01 00:26:47 +00:00
if ( OnInventoryFolderReceived = = null )
{
// Short-circuit early exit, we're not interested...
return ;
}
2007-02-24 00:17:42 +00:00
InventoryFolder iFolder = null ;
2007-03-05 23:37:47 +00:00
int numAttempts = 6 ;
int timeBetweenAttempts = 500 ;
2007-02-24 00:17:42 +00:00
while ( numAttempts - - > 0 )
{
foreach ( InventoryBase ib in root . GetContents ( ) )
{
if ( ib is InventoryFolder )
{
InventoryFolder tiFolder = ( InventoryFolder ) ib ;
if ( tiFolder . FolderID = = IncomingUUID )
{
iFolder = tiFolder ;
break ;
}
}
}
2007-03-01 00:26:47 +00:00
if ( iFolder ! = null )
2007-02-24 00:17:42 +00:00
{
2007-02-28 04:40:09 +00:00
try { OnInventoryFolderReceived ( fromAgentID , fromAgentName , parentEstateID , regionID , position , timestamp , iFolder ) ; }
catch ( Exception e ) { slClient . Log ( e . ToString ( ) , Helpers . LogLevel . Error ) ; }
2007-02-24 00:17:42 +00:00
return ;
} else {
2007-03-05 23:37:47 +00:00
Thread . Sleep ( timeBetweenAttempts ) ;
timeBetweenAttempts * = 2 ;
2007-02-24 00:17:42 +00:00
root . RequestDownloadContents ( false , true , false ) . RequestComplete . WaitOne ( 3000 , false ) ;
}
}
2007-02-28 05:16:00 +00:00
slClient . Log ( "Incoming folder [" + IncomingUUID . ToStringHyphenated ( ) + "] not found in inventory." , Helpers . LogLevel . Error ) ;
return ;
2007-01-23 01:22:58 +00:00
}
2007-03-01 00:26:47 +00:00
if ( OnInventoryItemReceived = = null )
{
// Short-circuit, early exit, we're not interested
return ;
}
2007-02-21 21:37:37 +00:00
// Make sure we have a folder lookup by type table ready.
2007-02-21 23:55:36 +00:00
lock ( FolderByType )
2007-01-23 01:22:58 +00:00
{
2007-02-21 23:55:36 +00:00
if ( FolderByType . Count = = 0 )
2007-01-23 01:22:58 +00:00
{
2007-02-21 23:55:36 +00:00
foreach ( InventoryBase ib in root . GetContents ( ) )
2007-01-23 01:22:58 +00:00
{
2007-02-21 23:55:36 +00:00
if ( ib is InventoryFolder )
{
InventoryFolder iFolder = ( InventoryFolder ) ib ;
FolderByType [ iFolder . Type ] = iFolder ;
}
2007-01-23 01:22:58 +00:00
}
}
}
2007-02-21 21:37:37 +00:00
// Get a reference to the incoming/receiving folder
if ( ! FolderByType . ContainsKey ( IncomingItemType ) )
{
slClient . Log ( "Incoming item specifies type (" + IncomingItemType + ") with no matching inventory folder found." , Helpers . LogLevel . Error ) ;
}
2007-02-21 21:45:56 +00:00
InventoryFolder incomingFolder = FolderByType [ IncomingItemType ] ;
2007-02-21 21:37:37 +00:00
InventoryItem incomingItem = null ;
2007-02-21 21:45:56 +00:00
2007-02-24 00:17:42 +00:00
// lock just incase another item comes into the same directory while processing this one.
2007-02-21 21:45:56 +00:00
lock ( incomingFolder )
2007-02-21 21:37:37 +00:00
{
2007-02-21 21:45:56 +00:00
// Refresh contents of receiving folder
2007-02-24 00:17:42 +00:00
incomingFolder . RequestDownloadContents ( false , false , true ) . RequestComplete . WaitOne ( 3000 , false ) ;
2007-02-21 21:37:37 +00:00
2007-02-24 00:17:42 +00:00
int numAttempts = 2 ;
while ( numAttempts - - > 0 )
2007-02-21 21:45:56 +00:00
{
2007-02-24 00:17:42 +00:00
// Search folder for incoming item
foreach ( InventoryBase ib2 in incomingFolder . GetContents ( ) )
2007-02-21 21:37:37 +00:00
{
2007-02-24 00:17:42 +00:00
if ( ib2 is InventoryItem )
2007-02-21 21:45:56 +00:00
{
2007-02-24 00:17:42 +00:00
InventoryItem tiItem = ( InventoryItem ) ib2 ;
if ( tiItem . ItemID = = IncomingUUID )
{
incomingItem = tiItem ;
break ;
}
2007-02-21 21:45:56 +00:00
}
2007-02-21 21:37:37 +00:00
}
2007-02-24 00:17:42 +00:00
// If found, send out notification
2007-03-01 00:26:47 +00:00
if ( incomingItem ! = null )
2007-02-24 00:17:42 +00:00
{
2007-02-28 04:40:09 +00:00
try { OnInventoryItemReceived ( fromAgentID , fromAgentName , parentEstateID , regionID , position , timestamp , incomingItem ) ; }
catch ( Exception e ) { slClient . Log ( e . ToString ( ) , Helpers . LogLevel . Error ) ; }
2007-02-24 00:17:42 +00:00
return ;
}
else
{
2007-02-28 02:19:35 +00:00
Thread . Sleep ( 500 ) ;
2007-02-24 00:17:42 +00:00
incomingFolder . RequestDownloadContents ( false , false , true ) . RequestComplete . WaitOne ( 3000 , false ) ;
}
2007-02-21 21:37:37 +00:00
}
}
2007-02-24 00:17:42 +00:00
slClient . Log ( "Incoming item/folder [" + IncomingUUID . ToStringHyphenated ( ) + "] not found in inventory." , Helpers . LogLevel . Error ) ;
2007-02-21 21:37:37 +00:00
2007-01-23 01:22:58 +00:00
}
}
2007-01-05 18:23:19 +00:00
/// <summary>
/// This is called in response to an item creation request
/// </summary>
/// <param name="packet"></param>
/// <param name="simulator"></param>
2006-10-21 02:52:28 +00:00
public void UpdateCreateInventoryItemHandler ( Packet packet , Simulator simulator )
{
2006-11-02 22:28:46 +00:00
#if DEBUG_PACKETS
2006-12-20 23:50:35 +00:00
slClient . DebugLog ( packet ) ;
2006-11-02 22:28:46 +00:00
#endif
2006-10-21 02:52:28 +00:00
2006-11-02 22:34:03 +00:00
if ( iiCreationInProgress ! = null )
2006-10-21 02:52:28 +00:00
{
UpdateCreateInventoryItemPacket reply = ( UpdateCreateInventoryItemPacket ) packet ;
2006-11-02 20:05:03 +00:00
// Use internal variable references, so we don't fire off any update code by using the public accessors
2006-10-21 05:53:58 +00:00
iiCreationInProgress . _ItemID = reply . InventoryData [ 0 ] . ItemID ;
2006-10-21 02:52:28 +00:00
iiCreationInProgress . _GroupOwned = reply . InventoryData [ 0 ] . GroupOwned ;
iiCreationInProgress . _SaleType = reply . InventoryData [ 0 ] . SaleType ;
iiCreationInProgress . _CreationDate = reply . InventoryData [ 0 ] . CreationDate ;
iiCreationInProgress . _BaseMask = reply . InventoryData [ 0 ] . BaseMask ;
2007-03-19 14:38:01 +00:00
iiCreationInProgress . _Name = Helpers . FieldToUTF8String ( reply . InventoryData [ 0 ] . Name ) ;
2006-10-21 02:52:28 +00:00
iiCreationInProgress . _InvType = reply . InventoryData [ 0 ] . InvType ;
iiCreationInProgress . _Type = reply . InventoryData [ 0 ] . Type ;
iiCreationInProgress . _AssetID = reply . InventoryData [ 0 ] . AssetID ;
iiCreationInProgress . _GroupID = reply . InventoryData [ 0 ] . GroupID ;
iiCreationInProgress . _SalePrice = reply . InventoryData [ 0 ] . SalePrice ;
iiCreationInProgress . _OwnerID = reply . InventoryData [ 0 ] . OwnerID ;
iiCreationInProgress . _CreatorID = reply . InventoryData [ 0 ] . CreatorID ;
iiCreationInProgress . _ItemID = reply . InventoryData [ 0 ] . ItemID ;
iiCreationInProgress . _FolderID = reply . InventoryData [ 0 ] . FolderID ;
iiCreationInProgress . _EveryoneMask = reply . InventoryData [ 0 ] . EveryoneMask ;
2007-03-19 14:38:01 +00:00
iiCreationInProgress . _Description = Helpers . FieldToUTF8String ( reply . InventoryData [ 0 ] . Description ) ;
2006-10-21 02:52:28 +00:00
iiCreationInProgress . _NextOwnerMask = reply . InventoryData [ 0 ] . NextOwnerMask ;
iiCreationInProgress . _GroupMask = reply . InventoryData [ 0 ] . GroupMask ;
iiCreationInProgress . _OwnerMask = reply . InventoryData [ 0 ] . OwnerMask ;
// NOT USED YET: iiCreationInProgress._CallbackID = reply.InventoryData[0].CallbackID;
2006-11-02 22:28:46 +00:00
ItemCreationCompleted . Set ( ) ;
2006-10-21 02:52:28 +00:00
}
else
{
2006-12-20 23:50:35 +00:00
slClient . DebugLog ( packet . ToString ( ) ) ;
2007-04-02 20:34:20 +00:00
// TODO: Looks like this packet may be sent in response to a Buy.
// Should probably use it to update local cached inventory, to show the bought item(s)
//
// throw new Exception("Received a packet for item creation, but no such response was expected. This is probably a bad thing...");
2006-10-21 02:52:28 +00:00
}
}
2006-12-19 23:13:04 +00:00
/// <summary>
2007-01-05 18:23:19 +00:00
/// Returned in response to a FetchInventoryDescendents request. Contains information about the
2006-12-19 23:13:04 +00:00
/// contents of a folder.
/// </summary>
/// <param name="packet"></param>
/// <param name="simulator"></param>
2006-10-21 05:53:58 +00:00
public void InventoryDescendentsHandler ( Packet packet , Simulator simulator )
{
2006-10-21 02:52:28 +00:00
InventoryDescendentsPacket reply = ( InventoryDescendentsPacket ) packet ;
2006-12-19 23:13:04 +00:00
// The UUID of this folder.
LLUUID uuidFolderID = reply . AgentData . FolderID ;
2007-02-24 00:17:42 +00:00
// 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
2007-03-01 00:26:47 +00:00
if ( ( ( CurrentlyDownloadingRequest ! = null ) & & ( CurrentlyDownloadingRequest . FolderID ! = uuidFolderID ) ) | | ( CurrentlyDownloadingRequest = = null ) )
2007-02-22 00:09:45 +00:00
{
2007-02-24 00:17:42 +00:00
// Release so that we can let other things look at and modify what is currently downloading.
CurrentlyDownloadingMutex . ReleaseMutex ( ) ;
// Log problem
2007-03-01 00:26:47 +00:00
LogDescendantQueueEvent ( "Unexpected descendent packet for folder: " + uuidFolderID . ToStringHyphenated ( ) ) ;
2007-02-24 00:17:42 +00:00
// Just discard this packet...
return ;
2007-02-22 00:09:45 +00:00
}
2006-12-19 23:13:04 +00:00
2007-01-05 02:32:21 +00:00
// Get the Inventory folder that we'll be updating
2007-01-05 22:38:15 +00:00
InventoryFolder InvFolderUpdating = ( InventoryFolder ) FoldersByUUID [ uuidFolderID ] ;
2007-01-05 02:32:21 +00:00
2007-03-01 22:41:31 +00:00
2006-12-19 23:13:04 +00:00
// Update Inventory Manager's last tick point, used for timeouts and such
2007-03-11 06:17:24 +00:00
// LastPacketRecievedAtTick = Environment.TickCount;
2006-10-21 02:52:28 +00:00
2006-12-19 23:13:04 +00:00
// Used to count the number of descendants received to see if we're finished or not.
int iDescendentsExpected = reply . AgentData . Descendents ;
2006-10-21 05:53:58 +00:00
int iDescendentsReceivedThisBlock = 0 ;
2006-10-21 02:52:28 +00:00
2007-02-24 00:17:42 +00:00
#region Handle Child Items
foreach ( InventoryDescendentsPacket . ItemDataBlock itemBlock in reply . ItemData )
2006-10-21 02:52:28 +00:00
{
2007-02-24 00:17:42 +00:00
// 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 )
2007-02-21 23:55:36 +00:00
{
2007-02-24 00:17:42 +00:00
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
2006-10-21 02:52:28 +00:00
{
2007-02-24 00:17:42 +00:00
InventoryItem TempInvItem = new InventoryItem ( this , itemBlock ) ;
2006-11-07 23:14:19 +00:00
2007-02-24 00:17:42 +00:00
if ( InvFolderUpdating . _Contents . Contains ( TempInvItem ) = = false )
2007-02-21 23:55:36 +00:00
{
2007-02-24 00:17:42 +00:00
#region Create an instance of the appriopriate Inventory class
if ( ( TempInvItem . InvType = = 7 ) & & ( TempInvItem . Type = = ( sbyte ) Asset . AssetType . Notecard ) )
2006-11-07 23:14:19 +00:00
{
2007-02-24 00:17:42 +00:00
InventoryItem temp = new InventoryNotecard ( this , TempInvItem ) ;
TempInvItem = temp ;
}
2007-05-07 04:52:36 +00:00
if ( ( TempInvItem . InvType = = 3 ) & & ( TempInvItem . Type = = ( sbyte ) Asset . AssetType . Landmark ) )
{
InventoryItem temp = new InventoryLandmark ( this , TempInvItem ) ;
TempInvItem = temp ;
}
2007-01-03 17:55:31 +00:00
2007-02-24 00:17:42 +00:00
if ( ( TempInvItem . InvType = = 0 ) & & ( TempInvItem . Type = = ( sbyte ) Asset . AssetType . Texture ) )
{
InventoryItem temp = new InventoryImage ( this , TempInvItem ) ;
TempInvItem = temp ;
}
2006-12-20 22:19:52 +00:00
2007-02-24 00:17:42 +00:00
if ( ( TempInvItem . InvType = = 10 ) & & ( TempInvItem . Type = = ( sbyte ) Asset . AssetType . LSLText ) )
{
InventoryItem temp = new InventoryScript ( this , TempInvItem ) ;
TempInvItem = temp ;
}
2006-12-20 22:19:52 +00:00
2007-02-24 00:17:42 +00:00
if ( ( TempInvItem . InvType = = 18 ) & &
(
( TempInvItem . Type = = ( sbyte ) Asset . AssetType . Bodypart )
| | ( TempInvItem . Type = = ( sbyte ) Asset . AssetType . Clothing )
)
)
{
InventoryItem temp = new InventoryWearable ( this , TempInvItem ) ;
TempInvItem = temp ;
2007-02-21 23:55:36 +00:00
}
2007-02-24 00:17:42 +00:00
#endregion
InvFolderUpdating . _Contents . Add ( TempInvItem ) ;
2006-10-21 02:52:28 +00:00
}
}
}
2007-02-24 00:17:42 +00:00
}
#endregion
2006-10-21 02:52:28 +00:00
2007-02-24 00:17:42 +00:00
#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 )
2006-10-21 02:52:28 +00:00
{
2007-02-24 00:17:42 +00:00
iDescendentsReceivedThisBlock + + ;
// See if the Incoming Folder already exists locally
if ( FoldersByUUID . ContainsKey ( IncomingFolderID ) )
2006-10-21 05:53:58 +00:00
{
2007-02-24 00:17:42 +00:00
InventoryFolder existingFolder = FoldersByUUID [ IncomingFolderID ] ;
existingFolder . _Name = IncomingName ;
existingFolder . _Type = IncomingType ;
2007-01-05 22:38:15 +00:00
2007-02-24 00:17:42 +00:00
// Check if parent of existing is the same as the incoming
if ( ! existingFolder . ParentID . Equals ( IncomingParentID ) )
2007-01-05 22:38:15 +00:00
{
2007-02-24 00:17:42 +00:00
// Remove existing from old parent
if ( FoldersByUUID . ContainsKey ( existingFolder . ParentID ) )
2007-01-05 22:38:15 +00:00
{
2007-02-24 00:17:42 +00:00
InventoryFolder ExistingParent = FoldersByUUID [ existingFolder . ParentID ] ;
if ( ExistingParent . _Contents . Contains ( existingFolder ) )
2007-01-05 22:38:15 +00:00
{
2007-02-24 00:17:42 +00:00
ExistingParent . _Contents . Remove ( existingFolder ) ;
2007-01-05 22:38:15 +00:00
}
2007-02-24 00:17:42 +00:00
}
2007-01-05 22:38:15 +00:00
2007-02-24 00:17:42 +00:00
// Set existings parent to new
existingFolder . _ParentID = IncomingParentID ;
2007-01-05 22:38:15 +00:00
2007-02-24 00:17:42 +00:00
// Connect existing folder to parent specified in new
if ( FoldersByUUID . ContainsKey ( IncomingParentID ) )
{
InventoryFolder ExistingParent = FoldersByUUID [ IncomingParentID ] ;
if ( ! ExistingParent . _Contents . Contains ( existingFolder ) )
2007-01-05 22:38:15 +00:00
{
2007-02-24 00:17:42 +00:00
ExistingParent . _Contents . Add ( existingFolder ) ;
2007-01-05 22:38:15 +00:00
}
}
}
2007-02-24 00:17:42 +00:00
}
else
{
InventoryFolder TempInvFolder = new InventoryFolder ( this , IncomingName , IncomingFolderID , IncomingParentID , IncomingType ) ;
2006-10-21 05:53:58 +00:00
2007-02-24 00:17:42 +00:00
// Add folder to Parent
if ( InvFolderUpdating . _Contents . Contains ( TempInvFolder ) = = false )
{
InvFolderUpdating . _Contents . Add ( TempInvFolder ) ;
}
2006-10-21 05:53:58 +00:00
2007-02-24 00:17:42 +00:00
// Add folder to local cache lookup
FoldersByUUID [ TempInvFolder . FolderID ] = TempInvFolder ;
2006-10-21 05:53:58 +00:00
2007-02-24 00:17:42 +00:00
}
2006-10-21 05:53:58 +00:00
2007-02-21 23:55:36 +00:00
2007-02-24 00:17:42 +00:00
// Do we recurse?
if ( CurrentlyDownloadingRequest . Recurse )
{
// It's not the root, should be safe to "recurse"
if ( ! IncomingFolderID . Equals ( slClient . Self . InventoryRootFolderUUID ) )
2006-10-21 05:53:58 +00:00
{
2007-03-05 23:00:03 +00:00
FolderRequestPrepend ( IncomingFolderID , CurrentlyDownloadingRequest . Recurse , CurrentlyDownloadingRequest . FetchFolders , CurrentlyDownloadingRequest . FetchItems , CurrentlyDownloadingRequest . Name + "/" + IncomingName ) ;
2006-10-21 05:53:58 +00:00
}
}
}
2007-02-24 00:17:42 +00:00
}
#endregion
2006-10-21 02:52:28 +00:00
2007-02-24 00:17:42 +00:00
// Update total number of descendants expected , and update the total downloaded
CurrentlyDownloadingRequest . Expected = iDescendentsExpected ;
CurrentlyDownloadingRequest . Received + = iDescendentsReceivedThisBlock ;
CurrentlyDownloadingRequest . LastReceivedAtTick = Environment . TickCount ;
2006-10-21 02:52:28 +00:00
2007-03-05 21:59:27 +00:00
if ( ( iDescendentsExpected > 1 ) & & ( iDescendentsReceivedThisBlock = = 0 ) )
2007-03-02 00:29:56 +00:00
{
slClient . Log ( "Received an InventoryDescendant packet where it indicated that there should be at least 1 descendant, but none were present... [" + CurrentlyDownloadingRequest . Name + "]" , Helpers . LogLevel . Warning ) ;
CurrentlyDownloadingRequest . Expected = 0 ;
}
2007-03-01 22:41:31 +00:00
if ( LogDescendantQueue )
{
slClient . Log ( "Received packet for: " + CurrentlyDownloadingRequest . ToString ( ) , Helpers . LogLevel . Info ) ;
}
2007-02-24 00:17:42 +00:00
// Check if we're finished
if ( CurrentlyDownloadingRequest . Received > = CurrentlyDownloadingRequest . Expected )
{
2007-03-01 00:26:47 +00:00
LogDescendantQueueEvent ( "Done downloading request: " + CurrentlyDownloadingRequest ) ;
2007-02-22 23:59:39 +00:00
2007-02-24 00:17:42 +00:00
// 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 ) ;
2006-10-21 05:53:58 +00:00
}
2007-02-24 00:17:42 +00:00
// Set Inventory Manager state to reflect that we're done with the current download
CurrentlyDownloadingAFolder = false ;
CurrentlyDownloadingRequest = null ;
2006-10-21 05:53:58 +00:00
}
2007-02-24 00:17:42 +00:00
// 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 ( ) ;
2006-10-21 05:53:58 +00:00
}
2007-01-05 02:32:21 +00:00
#endregion
2006-10-21 02:52:28 +00:00
}
}