From 6182ba84cd0611c560dbc25732bb22a750cc43cf Mon Sep 17 00:00:00 2001 From: Jim Radford Date: Thu, 29 Oct 2009 09:39:43 +0000 Subject: [PATCH] LIBOMV-686 Implements new event patterns based on the Microsoft Framework Design Guidelines in InventoryManager (Not every delegate is converted yet) LIBOMV-734 Thanks to Douglas R. Miles for converting the events in EstateManager over to new patterns LIBOMV-735 Removes redundant LoggedIn event from NetworkManager, when LoginProgress Status == Success you can reliably send packets to a simulator. If you send before this event is raised, an exception will be thrown and your application will crash, previously your request would just get sent to the bitbucket without any notice, Thanks lkalif for the help getting this bug fixed correctly git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@3187 52acb1d6-8a22-11de-b505-999d5b087335 --- OpenMetaverse.GUI/InventoryTree.cs | 6 +- OpenMetaverse/AgentManagerMovement.cs | 11 +- OpenMetaverse/AssetCache.cs | 20 +- OpenMetaverse/EstateTools.cs | 573 ++++-- OpenMetaverse/FriendsManager.cs | 12 +- OpenMetaverse/Inventory.cs | 193 +- OpenMetaverse/InventoryManager.cs | 1627 ++++++++++------- OpenMetaverse/Login.cs | 19 +- OpenMetaverse/NetworkManager.cs | 310 ++-- OpenMetaverse/TexturePipeline.cs | 8 +- .../Inventory/CreateNotecardCommand.cs | 16 +- .../Commands/Inventory/TaskRunningCommand.cs | 18 +- Programs/examples/TestClient/TestClient.cs | 18 +- 13 files changed, 1784 insertions(+), 1047 deletions(-) diff --git a/OpenMetaverse.GUI/InventoryTree.cs b/OpenMetaverse.GUI/InventoryTree.cs index dc8ca0bf..1fb690b0 100644 --- a/OpenMetaverse.GUI/InventoryTree.cs +++ b/OpenMetaverse.GUI/InventoryTree.cs @@ -166,7 +166,7 @@ namespace OpenMetaverse.GUI private void InitializeClient(GridClient client) { _Client = client; - _Client.Inventory.OnFolderUpdated += new InventoryManager.FolderUpdatedCallback(Inventory_OnFolderUpdated); + _Client.Inventory.FolderUpdated += Inventory_OnFolderUpdated; _Client.Network.LoginProgress += Network_OnLogin; } @@ -200,9 +200,9 @@ namespace OpenMetaverse.GUI } } - void Inventory_OnFolderUpdated(UUID folderID) + private void Inventory_OnFolderUpdated(object sender, FolderUpdatedEventArgs e) { - UpdateFolder(folderID); + UpdateFolder(e.FolderID); } void InventoryTree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) diff --git a/OpenMetaverse/AgentManagerMovement.cs b/OpenMetaverse/AgentManagerMovement.cs index 685cebcf..417ade87 100644 --- a/OpenMetaverse/AgentManagerMovement.cs +++ b/OpenMetaverse/AgentManagerMovement.cs @@ -473,7 +473,7 @@ namespace OpenMetaverse { Client = client; Camera = new AgentCamera(); - Client.Network.LoggedIn += Network_OnConnected; + Client.Network.LoginProgress += Network_OnConnected; Client.Network.Disconnected += Network_OnDisconnected; updateInterval = Settings.DEFAULT_AGENT_UPDATE_INTERVAL; } @@ -492,10 +492,13 @@ namespace OpenMetaverse CleanupTimer(); } - private void Network_OnConnected(object sender, LoggedInEventArgs e) + private void Network_OnConnected(object sender, LoginProgressEventArgs e) { - CleanupTimer(); - updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed), null, updateInterval, updateInterval); + if (e.Status == LoginStatus.Success) + { + CleanupTimer(); + updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed), null, updateInterval, updateInterval); + } } /// diff --git a/OpenMetaverse/AssetCache.cs b/OpenMetaverse/AssetCache.cs index 996e3c4d..e99c3b37 100644 --- a/OpenMetaverse/AssetCache.cs +++ b/OpenMetaverse/AssetCache.cs @@ -89,19 +89,17 @@ namespace OpenMetaverse public AssetCache(GridClient client) { Client = client; - Client.Network.LoggedIn += Network_OnConnected; - Client.Network.Disconnected += Network_OnDisconnected; - } + Client.Network.LoginProgress += delegate(object sender, LoginProgressEventArgs e) + { + if(e.Status == LoginStatus.Success) + { + SetupTimer(); + } + }; - private void Network_OnDisconnected(object sender, DisconnectedEventArgs e) - { - DestroyTimer(); - } - - private void Network_OnConnected(object sender, LoggedInEventArgs e) - { - SetupTimer(); + Client.Network.Disconnected += delegate(object sender, DisconnectedEventArgs e) { DestroyTimer(); }; } + /// /// Disposes cleanup timer diff --git a/OpenMetaverse/EstateTools.cs b/OpenMetaverse/EstateTools.cs index f2fe1907..b0f518c0 100644 --- a/OpenMetaverse/EstateTools.cs +++ b/OpenMetaverse/EstateTools.cs @@ -53,71 +53,6 @@ namespace OpenMetaverse /// Upper/lower texture boundaries for each corner of the sim public GroundTextureHeightSettings GroundTextureLimits; - #region Delegates - - /// - /// Triggered on LandStatReply when the report type is for "top colliders" - /// - /// - /// - public delegate void TopCollidersReplyCallback(int objectCount, Dictionary Tasks); - - /// - /// Triggered on LandStatReply when the report type is for "top scripts" - /// - /// - /// - public delegate void TopScriptsReplyCallback(int objectCount, Dictionary Tasks); - - /// - /// Triggered when the list of estate managers is received for the current estate - /// - /// - /// - /// - public delegate void EstateManagersReply(uint estateID, int count, List managers); - - /// - /// FIXME - Enumerate all params from EstateOwnerMessage packet - /// - /// - /// - /// - /// - public delegate void EstateUpdateInfoReply(string estateName, UUID estateOwner, uint estateID, bool denyNoPaymentInfo); - - public delegate void EstateManagersListReply(uint estateID, List managers); - - public delegate void EstateBansReply(uint estateID, int count, List banned); - - public delegate void EstateUsersReply(uint estateID, int count, List allowedUsers); - - public delegate void EstateGroupsReply(uint estateID, int count, List allowedGroups); - - public delegate void EstateCovenantReply(UUID covenantID, long timestamp, string estateName, UUID estateOwnerID); - #endregion - - #region Events - // Callback for LandStatReply packets - //public event LandStatReply OnLandStatReply; - /// Triggered upon a successful .GetTopColliders() - public event TopCollidersReplyCallback OnGetTopColliders; - /// Triggered upon a successful .GetTopScripts() - public event TopScriptsReplyCallback OnGetTopScripts; - /// Returned, along with other info, upon a successful .GetInfo() - public event EstateUpdateInfoReply OnGetEstateUpdateInfo; - /// Returned, along with other info, upon a successful .GetInfo() - public event EstateManagersReply OnGetEstateManagers; - /// Returned, along with other info, upon a successful .GetInfo() - public event EstateBansReply OnGetEstateBans; - /// Returned, along with other info, upon a successful .GetInfo() - public event EstateGroupsReply OnGetAllowedGroups; - /// Returned, along with other info, upon a successful .GetInfo() - public event EstateUsersReply OnGetAllowedUsers; - /// Triggered upon a successful .RequestCovenant() - public event EstateCovenantReply OnGetCovenant; - #endregion - /// /// Constructor for EstateTools class /// @@ -214,6 +149,197 @@ namespace OpenMetaverse public GroundTextureHeight NE; } #endregion + + #region Event delegates, Raise Events + + /// The event subscribers. null if no subcribers + private EventHandler m_TopCollidersReply; + + /// Raises the TopCollidersReply event + /// A TopCollidersReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnTopCollidersReply(TopCollidersReplyEventArgs e) + { + EventHandler handler = m_TopCollidersReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TopCollidersReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler TopCollidersReply + { + add { lock (m_TopCollidersReply_Lock) { m_TopCollidersReply += value; } } + remove { lock (m_TopCollidersReply_Lock) { m_TopCollidersReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_TopScriptsReply; + + /// Raises the TopScriptsReply event + /// A TopScriptsReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnTopScriptsReply(TopScriptsReplyEventArgs e) + { + EventHandler handler = m_TopScriptsReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TopScriptsReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler TopScriptsReply + { + add { lock (m_TopScriptsReply_Lock) { m_TopScriptsReply += value; } } + remove { lock (m_TopScriptsReply_Lock) { m_TopScriptsReply -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateUsersReply; + + /// Raises the EstateUsersReply event + /// A EstateUsersReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateUsersReply(EstateUsersReplyEventArgs e) + { + EventHandler handler = m_EstateUsersReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateUsersReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateUsersReply + { + add { lock (m_EstateUsersReply_Lock) { m_EstateUsersReply += value; } } + remove { lock (m_EstateUsersReply_Lock) { m_EstateUsersReply -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateGroupsReply; + + /// Raises the EstateGroupsReply event + /// A EstateGroupsReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateGroupsReply(EstateGroupsReplyEventArgs e) + { + EventHandler handler = m_EstateGroupsReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateGroupsReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateGroupsReply + { + add { lock (m_EstateGroupsReply_Lock) { m_EstateGroupsReply += value; } } + remove { lock (m_EstateGroupsReply_Lock) { m_EstateGroupsReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateManagersReply; + + /// Raises the EstateManagersReply event + /// A EstateManagersReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateManagersReply(EstateManagersReplyEventArgs e) + { + EventHandler handler = m_EstateManagersReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateManagersReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateManagersReply + { + add { lock (m_EstateManagersReply_Lock) { m_EstateManagersReply += value; } } + remove { lock (m_EstateManagersReply_Lock) { m_EstateManagersReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateBansReply; + + /// Raises the EstateBansReply event + /// A EstateBansReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateBansReply(EstateBansReplyEventArgs e) + { + EventHandler handler = m_EstateBansReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateBansReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateBansReply + { + add { lock (m_EstateBansReply_Lock) { m_EstateBansReply += value; } } + remove { lock (m_EstateBansReply_Lock) { m_EstateBansReply -= value; } } + } + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateCovenantReply; + + /// Raises the EstateCovenantReply event + /// A EstateCovenantReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateCovenantReply(EstateCovenantReplyEventArgs e) + { + EventHandler handler = m_EstateCovenantReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateCovenantReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateCovenantReply + { + add { lock (m_EstateCovenantReply_Lock) { m_EstateCovenantReply += value; } } + remove { lock (m_EstateCovenantReply_Lock) { m_EstateCovenantReply -= value; } } + } + + + /// The event subscribers. null if no subcribers + private EventHandler m_EstateUpdateInfoReply; + + /// Raises the EstateUpdateInfoReply event + /// A EstateUpdateInfoReplyEventArgs object containing the + /// data returned from the data server + protected virtual void OnEstateUpdateInfoReply(EstateUpdateInfoReplyEventArgs e) + { + EventHandler handler = m_EstateUpdateInfoReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_EstateUpdateInfoReply_Lock = new object(); + + /// Raised when the data server responds to a request. + public event EventHandler EstateUpdateInfoReply + { + add { lock (m_EstateUpdateInfoReply_Lock) { m_EstateUpdateInfoReply += value; } } + remove { lock (m_EstateUpdateInfoReply_Lock) { m_EstateUpdateInfoReply -= value; } } + } + #endregion + #region Public Methods /// /// Requests estate information such as top scripts and colliders @@ -624,18 +750,11 @@ namespace OpenMetaverse protected void EstateCovenantReplyHandler(object sender, PacketReceivedEventArgs e) { EstateCovenantReplyPacket reply = (EstateCovenantReplyPacket)e.Packet; - if (OnGetCovenant != null) - { - try - { - OnGetCovenant( - reply.Data.CovenantID, - reply.Data.CovenantTimestamp, - Utils.BytesToString(reply.Data.EstateName), - reply.Data.EstateOwnerID); - } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } - } + OnEstateCovenantReply(new EstateCovenantReplyEventArgs( + reply.Data.CovenantID, + reply.Data.CovenantTimestamp, + Utils.BytesToString(reply.Data.EstateName), + reply.Data.EstateOwnerID)); } /// Process an incoming packet and raise the appropriate events @@ -663,14 +782,7 @@ namespace OpenMetaverse if (Utils.BytesToUInt(message.ParamList[8].Parameter) == 0) denyNoPaymentInfo = true; else denyNoPaymentInfo = false; - if (OnGetEstateUpdateInfo != null) - { - try - { - OnGetEstateUpdateInfo(estateName, estateOwner, estateID, denyNoPaymentInfo); - } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } - } + OnEstateUpdateInfoReply(new EstateUpdateInfoReplyEventArgs(estateName, estateOwner, estateID, denyNoPaymentInfo)); } else if (method == "setaccess") @@ -688,7 +800,7 @@ namespace OpenMetaverse switch (accessType) { case EstateAccessReplyDelta.EstateManagers: - if (OnGetEstateManagers != null) + //if (OnGetEstateManagers != null) { if (message.ParamList.Length > 5) { @@ -703,14 +815,13 @@ namespace OpenMetaverse } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } - try { OnGetEstateManagers(estateID, count, managers); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + OnEstateManagersReply(new EstateManagersReplyEventArgs(estateID, count, managers)); } } break; case EstateAccessReplyDelta.EstateBans: - if (OnGetEstateBans != null) + //if (OnGetEstateBans != null) { if (message.ParamList.Length > 6) { @@ -725,14 +836,13 @@ namespace OpenMetaverse } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } - try { OnGetEstateBans(estateID, count, bannedUsers); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + OnEstateBansReply(new EstateBansReplyEventArgs(estateID, count, bannedUsers)); } } break; case EstateAccessReplyDelta.AllowedUsers: - if (OnGetAllowedUsers != null) + //if (OnGetAllowedUsers != null) { if (message.ParamList.Length > 5) { @@ -747,14 +857,13 @@ namespace OpenMetaverse } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } - try { OnGetAllowedUsers(estateID, count, allowedUsers); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + OnEstateUsersReply(new EstateUsersReplyEventArgs(estateID, count, allowedUsers)); } } break; case EstateAccessReplyDelta.AllowedGroups: - if (OnGetAllowedGroups != null) + //if (OnGetAllowedGroups != null) { if (message.ParamList.Length > 5) { @@ -769,8 +878,7 @@ namespace OpenMetaverse } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } - try { OnGetAllowedGroups(estateID, count, allowedGroups); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + OnEstateGroupsReply(new EstateGroupsReplyEventArgs(estateID, count, allowedGroups)); } } break; @@ -785,7 +893,7 @@ namespace OpenMetaverse protected void LandStatReplyHandler(object sender, PacketReceivedEventArgs e) { //if (OnLandStatReply != null || OnGetTopScripts != null || OnGetTopColliders != null) - if (OnGetTopScripts != null || OnGetTopColliders != null) + //if (OnGetTopScripts != null || OnGetTopColliders != null) { LandStatReplyPacket p = (LandStatReplyPacket)e.Packet; Dictionary Tasks = new Dictionary(); @@ -804,15 +912,13 @@ namespace OpenMetaverse LandStatReportType type = (LandStatReportType)p.RequestData.ReportType; - if (OnGetTopScripts != null && type == LandStatReportType.TopScripts) + if (type == LandStatReportType.TopScripts) { - try { OnGetTopScripts((int)p.RequestData.TotalObjectCount, Tasks); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + OnTopScriptsReply(new TopScriptsReplyEventArgs((int)p.RequestData.TotalObjectCount, Tasks)); } - else if (OnGetTopColliders != null && type == LandStatReportType.TopColliders) + else if (type == LandStatReportType.TopColliders) { - try { OnGetTopColliders((int)p.RequestData.TotalObjectCount, Tasks); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } + OnTopCollidersReply(new TopCollidersReplyEventArgs((int) p.RequestData.TotalObjectCount, Tasks)); } /* @@ -832,4 +938,263 @@ namespace OpenMetaverse } #endregion } + #region EstateTools EventArgs Classes + + /// Raised on LandStatReply when the report type is for "top colliders" + public class TopCollidersReplyEventArgs : EventArgs + { + private readonly int m_objectCount; + private readonly Dictionary m_Tasks; + + /// + /// The number of returned items in LandStatReply + /// + public int ObjectCount { get { return m_objectCount; } } + /// + /// A Dictionary of Object UUIDs to tasks returned in LandStatReply + /// + public Dictionary Tasks { get { return m_Tasks; } } + + /// Construct a new instance of the TopCollidersReplyEventArgs class + /// The number of returned items in LandStatReply + /// Dictionary of Object UUIDs to tasks returned in LandStatReply + public TopCollidersReplyEventArgs(int objectCount, Dictionary tasks) + { + this.m_objectCount = objectCount; + this.m_Tasks = tasks; + } + } + + /// Raised on LandStatReply when the report type is for "top Scripts" + public class TopScriptsReplyEventArgs : EventArgs + { + private readonly int m_objectCount; + private readonly Dictionary m_Tasks; + + /// + /// The number of scripts returned in LandStatReply + /// + public int ObjectCount { get { return m_objectCount; } } + /// + /// A Dictionary of Object UUIDs to tasks returned in LandStatReply + /// + public Dictionary Tasks { get { return m_Tasks; } } + + /// Construct a new instance of the TopScriptsReplyEventArgs class + /// The number of returned items in LandStatReply + /// Dictionary of Object UUIDs to tasks returned in LandStatReply + public TopScriptsReplyEventArgs(int objectCount, Dictionary tasks) + { + this.m_objectCount = objectCount; + this.m_Tasks = tasks; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateBansReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_banned; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned itmes + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of Banned Users + /// + public List Banned { get { return m_banned; } } + + /// Construct a new instance of the EstateBansReplyEventArgs class + /// The estate's identifier on the grid + /// The number of returned items in LandStatReply + /// User UUIDs banned + public EstateBansReplyEventArgs(uint estateID, int count, List banned) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_banned = banned; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateUsersReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_allowedUsers; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned items + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of Allowed Users + /// + public List AllowedUsers { get { return m_allowedUsers; } } + + /// Construct a new instance of the EstateUsersReplyEventArgs class + /// The estate's identifier on the grid + /// The number of users + /// Allowed users UUIDs + public EstateUsersReplyEventArgs(uint estateID, int count, List allowedUsers) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_allowedUsers = allowedUsers; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateGroupsReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_allowedGroups; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned items + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of Allowed Groups + /// + public List AllowedGroups { get { return m_allowedGroups; } } + + /// Construct a new instance of the EstateGroupsReplyEventArgs class + /// The estate's identifier on the grid + /// The number of Groups + /// Allowed Groups UUIDs + public EstateGroupsReplyEventArgs(uint estateID, int count, List allowedGroups) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_allowedGroups = allowedGroups; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateManagersReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly int m_count; + private readonly List m_Managers; + + /// + /// The identifier of the estate + /// + public uint EstateID { get { return m_estateID; } } + /// + /// The number of returned items + /// + public int Count { get { return m_count; } } + /// + /// List of UUIDs of the Estate's Managers + /// + public List Managers { get { return m_Managers; } } + + /// Construct a new instance of the EstateManagersReplyEventArgs class + /// The estate's identifier on the grid + /// The number of Managers + /// Managers UUIDs + public EstateManagersReplyEventArgs(uint estateID, int count, List managers) + { + this.m_estateID = estateID; + this.m_count = count; + this.m_Managers = managers; + } + } + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateCovenantReplyEventArgs : EventArgs + { + private readonly UUID m_covenantID; + private readonly long m_timestamp; + private readonly string m_estateName; + private readonly UUID m_estateOwnerID; + + /// + /// The Covenant + /// + public UUID CovenantID { get { return m_covenantID; } } + /// + /// The timestamp + /// + public long Timestamp { get { return m_timestamp; } } + /// + /// The Estate name + /// + public String EstateName { get { return m_estateName; } } + /// + /// The Estate Owner's ID (can be a GroupID) + /// + public UUID EstateOwnerID { get { return m_estateOwnerID; } } + + /// Construct a new instance of the EstateCovenantReplyEventArgs class + /// The Covenant ID + /// The timestamp + /// The estate's name + /// The Estate Owner's ID (can be a GroupID) + public EstateCovenantReplyEventArgs(UUID covenantID, long timestamp, string estateName, UUID estateOwnerID) + { + this.m_covenantID = covenantID; + this.m_timestamp = timestamp; + this.m_estateName = estateName; + this.m_estateOwnerID = estateOwnerID; + + } + } + + + /// Returned, along with other info, upon a successful .RequestInfo() + public class EstateUpdateInfoReplyEventArgs : EventArgs + { + private readonly uint m_estateID; + private readonly bool m_denyNoPaymentInfo; + private readonly string m_estateName; + private readonly UUID m_estateOwner; + + /// + /// The estate's name + /// + public String EstateName { get { return m_estateName; } } + /// + /// The Estate Owner's ID (can be a GroupID) + /// + public UUID EstateOwner { get { return m_estateOwner; } } + /// + /// The identifier of the estate on the grid + /// + public uint EstateID { get { return m_estateID; } } + /// + public bool DenyNoPaymentInfo { get { return m_denyNoPaymentInfo; } } + + /// Construct a new instance of the EstateUpdateInfoReplyEventArgs class + /// The estate's name + /// The Estate Owners ID (can be a GroupID) + /// The estate's identifier on the grid + /// + public EstateUpdateInfoReplyEventArgs(string estateName, UUID estateOwner, uint estateID, bool denyNoPaymentInfo) + { + this.m_estateName = estateName; + this.m_estateOwner = estateOwner; + this.m_estateID = estateID; + this.m_denyNoPaymentInfo = denyNoPaymentInfo; + + } + } + #endregion } diff --git a/OpenMetaverse/FriendsManager.cs b/OpenMetaverse/FriendsManager.cs index 16be6227..d16d9233 100644 --- a/OpenMetaverse/FriendsManager.cs +++ b/OpenMetaverse/FriendsManager.cs @@ -453,7 +453,7 @@ namespace OpenMetaverse { Client = client; - Client.Network.LoggedIn += Network_OnConnect; + Client.Network.LoginProgress += Network_OnConnect; Client.Avatars.UUIDNameReply += new EventHandler(Avatars_OnAvatarNames); Client.Self.IM += Self_IM; @@ -662,11 +662,13 @@ namespace OpenMetaverse #region Internal events - /// Process an incoming packet and raise the appropriate events - /// The sender - /// The EventArgs object containing the packet data - private void Network_OnConnect(object sender, LoggedInEventArgs e) + private void Network_OnConnect(object sender, LoginProgressEventArgs e) { + if (e.Status != LoginStatus.Success) + { + return; + } + List names = new List(); if (FriendList.Count > 0) diff --git a/OpenMetaverse/Inventory.cs b/OpenMetaverse/Inventory.cs index 438b2171..34a772e6 100644 --- a/OpenMetaverse/Inventory.cs +++ b/OpenMetaverse/Inventory.cs @@ -51,40 +51,79 @@ namespace OpenMetaverse /// public class Inventory { - /// - /// Delegate to use for the OnInventoryObjectUpdated event. - /// - /// The state of the InventoryObject before the update occured. - /// The state of the InventoryObject after the update occured. - public delegate void InventoryObjectUpdated(InventoryBase oldObject, InventoryBase newObject); - /// - /// Delegate to use for the OnInventoryObjectRemoved event. - /// - /// The InventoryObject that was removed. - public delegate void InventoryObjectRemoved(InventoryBase obj); - /// - /// Delegate to use for the OnInventoryObjectUpdated event. - /// - /// The InventoryObject that has been stored. - public delegate void InventoryObjectAdded(InventoryBase obj); + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectUpdated; - /// - /// Called when an InventoryObject's state is changed. - /// - public event InventoryObjectUpdated OnInventoryObjectUpdated; - /// - /// Called when an item or folder is removed from inventory. - /// - public event InventoryObjectRemoved OnInventoryObjectRemoved; - /// - /// Called when an item is first added to the local inventory store. - /// This will occur most frequently when we're initially downloading - /// the inventory from the server. - /// - /// This will also fire when another avatar or object offers us inventory - /// - public event InventoryObjectAdded OnInventoryObjectAdded; + ///Raises the InventoryObjectUpdated Event + /// A InventoryObjectUpdatedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectUpdated(InventoryObjectUpdatedEventArgs e) + { + EventHandler handler = m_InventoryObjectUpdated; + if (handler != null) + handler(this, e); + } + /// Thread sync lock object + private readonly object m_InventoryObjectUpdatedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler InventoryObjectUpdated + { + add { lock (m_InventoryObjectUpdatedLock) { m_InventoryObjectUpdated += value; } } + remove { lock (m_InventoryObjectUpdatedLock) { m_InventoryObjectUpdated -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectRemoved; + + ///Raises the InventoryObjectRemoved Event + /// A InventoryObjectRemovedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectRemoved(InventoryObjectRemovedEventArgs e) + { + EventHandler handler = m_InventoryObjectRemoved; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InventoryObjectRemovedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler InventoryObjectRemoved + { + add { lock (m_InventoryObjectRemovedLock) { m_InventoryObjectRemoved += value; } } + remove { lock (m_InventoryObjectRemovedLock) { m_InventoryObjectRemoved -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectAdded; + + ///Raises the InventoryObjectAdded Event + /// A InventoryObjectAddedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectAdded(InventoryObjectAddedEventArgs e) + { + EventHandler handler = m_InventoryObjectAdded; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InventoryObjectAddedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler InventoryObjectAdded + { + add { lock (m_InventoryObjectAddedLock) { m_InventoryObjectAdded += value; } } + remove { lock (m_InventoryObjectAddedLock) { m_InventoryObjectAdded -= value; } } + } + /// /// The root folder of this avatars inventory /// @@ -212,8 +251,7 @@ namespace OpenMetaverse { // Fetch the parent List fetchreq = new List(1); - fetchreq.Add(item.ParentUUID); - //Manager.FetchInventory(fetchreq); // we cant fetch folder data! :-O + fetchreq.Add(item.ParentUUID); } } @@ -238,7 +276,10 @@ namespace OpenMetaverse itemNode.Parent = itemParent; - FireOnInventoryObjectUpdated(itemNode.Data, item); + if (m_InventoryObjectUpdated != null) + { + OnInventoryObjectUpdated(new InventoryObjectUpdatedEventArgs(itemNode.Data, item)); + } itemNode.Data = item; } @@ -246,7 +287,10 @@ namespace OpenMetaverse { itemNode = new InventoryNode(item, itemParent); Items.Add(item.UUID, itemNode); - FireOnInventoryObjectAdded(item); + if (m_InventoryObjectAdded != null) + { + OnInventoryObjectAdded(new InventoryObjectAddedEventArgs(item)); + } } } } @@ -271,7 +315,10 @@ namespace OpenMetaverse lock (node.Parent.Nodes.SyncRoot) node.Parent.Nodes.Remove(item.UUID); Items.Remove(item.UUID); - FireOnInventoryObjectRemoved(item); + if (m_InventoryObjectRemoved != null) + { + OnInventoryObjectRemoved(new InventoryObjectRemovedEventArgs(item)); + } } // In case there's a new parent: @@ -474,36 +521,46 @@ namespace OpenMetaverse } #endregion Operators - - #region Event Firing - - protected void FireOnInventoryObjectUpdated(InventoryBase oldObject, InventoryBase newObject) - { - if (OnInventoryObjectUpdated != null) - { - try { OnInventoryObjectUpdated(oldObject, newObject); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } - } - } - - protected void FireOnInventoryObjectRemoved(InventoryBase obj) - { - if (OnInventoryObjectRemoved != null) - { - try { OnInventoryObjectRemoved(obj); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } - } - } - - protected void FireOnInventoryObjectAdded(InventoryBase obj) - { - if (OnInventoryObjectAdded != null) - { - try { OnInventoryObjectAdded(obj); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } - } - } - - #endregion + } + #region EventArgs classes + + public class InventoryObjectUpdatedEventArgs : EventArgs + { + private readonly InventoryBase m_OldObject; + private readonly InventoryBase m_NewObject; + + public InventoryBase OldObject { get { return m_OldObject; } } + public InventoryBase NewObject { get { return m_NewObject; } } + + public InventoryObjectUpdatedEventArgs(InventoryBase oldObject, InventoryBase newObject) + { + this.m_OldObject = oldObject; + this.m_NewObject = newObject; + } + } + + public class InventoryObjectRemovedEventArgs : EventArgs + { + private readonly InventoryBase m_Obj; + + public InventoryBase Obj { get { return m_Obj; } } + public InventoryObjectRemovedEventArgs(InventoryBase obj) + { + this.m_Obj = obj; + } + } + + public class InventoryObjectAddedEventArgs : EventArgs + { + private readonly InventoryBase m_Obj; + + public InventoryBase Obj { get { return m_Obj; } } + + public InventoryObjectAddedEventArgs(InventoryBase obj) + { + this.m_Obj = obj; + } + } + #endregion EventArgs } diff --git a/OpenMetaverse/InventoryManager.cs b/OpenMetaverse/InventoryManager.cs index bc270dfe..0aa63ac8 100644 --- a/OpenMetaverse/InventoryManager.cs +++ b/OpenMetaverse/InventoryManager.cs @@ -153,7 +153,7 @@ namespace OpenMetaverse public virtual void GetObjectData(SerializationInfo info, StreamingContext ctxt) { info.AddValue("UUID", UUID); - info.AddValue("ParentUUID",ParentUUID ); + info.AddValue("ParentUUID", ParentUUID); info.AddValue("Name", Name); info.AddValue("OwnerID", OwnerID); } @@ -244,7 +244,7 @@ namespace OpenMetaverse /// Construct a new InventoryItem object /// /// The of the item - public InventoryItem(UUID itemID) + public InventoryItem(UUID itemID) : base(itemID) { } /// @@ -281,21 +281,22 @@ namespace OpenMetaverse /// /// /// - public InventoryItem(SerializationInfo info, StreamingContext ctxt) : base (info,ctxt) + public InventoryItem(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - AssetUUID = (UUID)info.GetValue("AssetUUID", typeof(UUID)); - Permissions =(Permissions)info.GetValue("Permissions",typeof(Permissions)); - AssetType = (AssetType)info.GetValue("AssetType", typeof(AssetType)); - InventoryType = (InventoryType)info.GetValue("InventoryType", typeof(InventoryType)); - CreatorID = (UUID)info.GetValue("CreatorID", typeof(UUID)); - Description = (string)info.GetValue("Description", typeof(string)); - GroupID= (UUID)info.GetValue("GroupID", typeof(UUID)); - GroupOwned = (bool)info.GetValue("GroupOwned", typeof(bool)); - SalePrice = (int)info.GetValue("SalePrice", typeof(int)); - SaleType = (SaleType)info.GetValue("SaleType", typeof(SaleType)); - Flags = (uint)info.GetValue("Flags", typeof(uint)); - CreationDate = (DateTime)info.GetValue("CreationDate", typeof(DateTime)); - LastOwnerID = (UUID)info.GetValue("LastOwnerID", typeof(UUID)); + AssetUUID = (UUID)info.GetValue("AssetUUID", typeof(UUID)); + Permissions = (Permissions)info.GetValue("Permissions", typeof(Permissions)); + AssetType = (AssetType)info.GetValue("AssetType", typeof(AssetType)); + InventoryType = (InventoryType)info.GetValue("InventoryType", typeof(InventoryType)); + CreatorID = (UUID)info.GetValue("CreatorID", typeof(UUID)); + Description = (string)info.GetValue("Description", typeof(string)); + GroupID = (UUID)info.GetValue("GroupID", typeof(UUID)); + GroupOwned = (bool)info.GetValue("GroupOwned", typeof(bool)); + SalePrice = (int)info.GetValue("SalePrice", typeof(int)); + SaleType = (SaleType)info.GetValue("SaleType", typeof(SaleType)); + Flags = (uint)info.GetValue("Flags", typeof(uint)); + CreationDate = (DateTime)info.GetValue("CreationDate", typeof(DateTime)); + LastOwnerID = (UUID)info.GetValue("LastOwnerID", typeof(UUID)); } /// @@ -360,94 +361,102 @@ namespace OpenMetaverse /// InventoryTexture Class representing a graphical image /// /// - public class InventoryTexture : InventoryItem - { + public class InventoryTexture : InventoryItem + { /// /// Construct an InventoryTexture object /// /// A which becomes the /// objects AssetUUID - public InventoryTexture(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Texture; - } + public InventoryTexture(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Texture; + } /// /// Construct an InventoryTexture object from a serialization stream /// - public InventoryTexture(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryTexture(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Texture; + InventoryType = InventoryType.Texture; } } /// /// InventorySound Class representing a playable sound /// - public class InventorySound : InventoryItem + public class InventorySound : InventoryItem { /// /// Construct an InventorySound object /// /// A which becomes the /// objects AssetUUID - public InventorySound(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Sound; - } + public InventorySound(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Sound; + } /// /// Construct an InventorySound object from a serialization stream /// - public InventorySound(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventorySound(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Sound; + InventoryType = InventoryType.Sound; } } /// /// InventoryCallingCard Class, contains information on another avatar /// - public class InventoryCallingCard : InventoryItem + public class InventoryCallingCard : InventoryItem { /// /// Construct an InventoryCallingCard object /// /// A which becomes the /// objects AssetUUID - public InventoryCallingCard(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.CallingCard; + public InventoryCallingCard(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.CallingCard; } /// /// Construct an InventoryCallingCard object from a serialization stream /// - public InventoryCallingCard(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryCallingCard(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.CallingCard; + InventoryType = InventoryType.CallingCard; } } /// /// InventoryLandmark Class, contains details on a specific location /// - public class InventoryLandmark : InventoryItem + public class InventoryLandmark : InventoryItem { /// /// Construct an InventoryLandmark object /// /// A which becomes the /// objects AssetUUID - public InventoryLandmark(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Landmark; + public InventoryLandmark(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Landmark; } /// /// Construct an InventoryLandmark object from a serialization stream /// - public InventoryLandmark(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryLandmark(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { InventoryType = InventoryType.Landmark; @@ -470,24 +479,26 @@ namespace OpenMetaverse /// /// InventoryObject Class contains details on a primitive or coalesced set of primitives /// - public class InventoryObject : InventoryItem + public class InventoryObject : InventoryItem { /// /// Construct an InventoryObject object /// /// A which becomes the /// objects AssetUUID - public InventoryObject(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Object; + public InventoryObject(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Object; } /// /// Construct an InventoryObject object from a serialization stream /// - public InventoryObject(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryObject(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Object; + InventoryType = InventoryType.Object; } /// @@ -512,24 +523,26 @@ namespace OpenMetaverse /// /// InventoryNotecard Class, contains details on an encoded text document /// - public class InventoryNotecard : InventoryItem + public class InventoryNotecard : InventoryItem { /// /// Construct an InventoryNotecard object /// /// A which becomes the /// objects AssetUUID - public InventoryNotecard(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Notecard; + public InventoryNotecard(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Notecard; } /// /// Construct an InventoryNotecard object from a serialization stream /// - public InventoryNotecard(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryNotecard(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Notecard; + InventoryType = InventoryType.Notecard; } } @@ -537,96 +550,104 @@ namespace OpenMetaverse /// InventoryCategory Class /// /// TODO: Is this even used for anything? - public class InventoryCategory : InventoryItem + public class InventoryCategory : InventoryItem { /// /// Construct an InventoryCategory object /// /// A which becomes the /// objects AssetUUID - public InventoryCategory(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Category; - } + public InventoryCategory(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Category; + } /// /// Construct an InventoryCategory object from a serialization stream /// - public InventoryCategory(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryCategory(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Category; + InventoryType = InventoryType.Category; } } /// /// InventoryLSL Class, represents a Linden Scripting Language object /// - public class InventoryLSL : InventoryItem + public class InventoryLSL : InventoryItem { /// /// Construct an InventoryLSL object /// /// A which becomes the /// objects AssetUUID - public InventoryLSL(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.LSL; - } + public InventoryLSL(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.LSL; + } /// /// Construct an InventoryLSL object from a serialization stream /// - public InventoryLSL(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryLSL(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.LSL; + InventoryType = InventoryType.LSL; } } /// /// InventorySnapshot Class, an image taken with the viewer /// - public class InventorySnapshot : InventoryItem + public class InventorySnapshot : InventoryItem { /// /// Construct an InventorySnapshot object /// /// A which becomes the /// objects AssetUUID - public InventorySnapshot(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Snapshot; - } + public InventorySnapshot(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Snapshot; + } /// /// Construct an InventorySnapshot object from a serialization stream /// - public InventorySnapshot(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventorySnapshot(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Snapshot; + InventoryType = InventoryType.Snapshot; } } /// /// InventoryAttachment Class, contains details on an attachable object /// - public class InventoryAttachment : InventoryItem + public class InventoryAttachment : InventoryItem { /// /// Construct an InventoryAttachment object /// /// A which becomes the /// objects AssetUUID - public InventoryAttachment(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Attachment; + public InventoryAttachment(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Attachment; } /// /// Construct an InventoryAttachment object from a serialization stream /// - public InventoryAttachment(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryAttachment(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Attachment; + InventoryType = InventoryType.Attachment; } /// @@ -654,9 +675,10 @@ namespace OpenMetaverse /// /// Construct an InventoryWearable object from a serialization stream /// - public InventoryWearable(SerializationInfo info, StreamingContext ctxt) : base(info, ctxt) + public InventoryWearable(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Wearable; + InventoryType = InventoryType.Wearable; } /// @@ -672,53 +694,57 @@ namespace OpenMetaverse /// /// InventoryAnimation Class, A bvh encoded object which animates an avatar /// - public class InventoryAnimation : InventoryItem + public class InventoryAnimation : InventoryItem { /// /// Construct an InventoryAnimation object /// /// A which becomes the /// objects AssetUUID - public InventoryAnimation(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Animation; + public InventoryAnimation(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Animation; } - /// + /// /// Construct an InventoryAnimation object from a serialization stream /// - public InventoryAnimation(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryAnimation(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Animation; + InventoryType = InventoryType.Animation; } - + } /// /// InventoryGesture Class, details on a series of animations, sounds, and actions /// - public class InventoryGesture : InventoryItem + public class InventoryGesture : InventoryItem { /// /// Construct an InventoryGesture object /// /// A which becomes the /// objects AssetUUID - public InventoryGesture(UUID itemID) : base(itemID) - { - InventoryType = InventoryType.Gesture; - } + public InventoryGesture(UUID itemID) + : base(itemID) + { + InventoryType = InventoryType.Gesture; + } /// /// Construct an InventoryGesture object from a serialization stream /// - public InventoryGesture(SerializationInfo info, StreamingContext ctxt): base(info, ctxt) + public InventoryGesture(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { - InventoryType = InventoryType.Gesture; + InventoryType = InventoryType.Gesture; } } - + /// /// A folder contains s and has certain attributes specific /// to itself @@ -737,7 +763,7 @@ namespace OpenMetaverse /// /// UUID of the folder public InventoryFolder(UUID itemID) - : base(itemID) + : base(itemID) { PreferredType = AssetType.Unknown; Version = 1; @@ -758,7 +784,7 @@ namespace OpenMetaverse /// override public void GetObjectData(SerializationInfo info, StreamingContext ctxt) { - base.GetObjectData(info,ctxt); + base.GetObjectData(info, ctxt); info.AddValue("PreferredType", PreferredType, typeof(AssetType)); info.AddValue("Version", Version); info.AddValue("DescendentCount", DescendentCount); @@ -767,10 +793,11 @@ namespace OpenMetaverse /// /// Construct an InventoryFolder object from a serialization stream /// - public InventoryFolder(SerializationInfo info, StreamingContext ctxt) : base (info, ctxt) + public InventoryFolder(SerializationInfo info, StreamingContext ctxt) + : base(info, ctxt) { PreferredType = (AssetType)info.GetValue("PreferredType", typeof(AssetType)); - Version=(int)info.GetValue("Version",typeof(int)); + Version = (int)info.GetValue("Version", typeof(int)); DescendentCount = (int)info.GetValue("DescendentCount", typeof(int)); } @@ -863,58 +890,153 @@ namespace OpenMetaverse /// public delegate void ItemCopiedCallback(InventoryBase item); - /// - /// - /// - /// - public delegate void ItemReceivedCallback(InventoryItem item); + /// The event subscribers, null of no subscribers + private EventHandler m_ItemReceived; - /// - /// Callback for an inventory folder updating - /// - /// UUID of the folder that was updated - public delegate void FolderUpdatedCallback(UUID folderID); + ///Raises the ItemReceived Event + /// A ItemReceivedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnItemReceived(ItemReceivedEventArgs e) + { + EventHandler handler = m_ItemReceived; + if (handler != null) + handler(this, e); + } - /// - /// Callback for when an inventory item is offered to us by another avatar or an object - /// - /// A object containing specific - /// details on the item being offered, eg who its from - /// The AssetType being offered - /// Will be null if item is offered from an object - /// will be true of item is offered from an object - /// Return true to accept the offer, or false to decline it - public delegate bool ObjectOfferedCallback(InstantMessage offerDetails, AssetType type, UUID objectID, bool fromTask); + /// Thread sync lock object + private readonly object m_ItemReceivedLock = new object(); - /// - /// Callback when an inventory object is accepted and received from a - /// task inventory. This is the callback in which you actually get - /// the ItemID, as in ObjectOfferedCallback it is null when received - /// from a task. - /// - /// - /// - /// - /// - /// - public delegate void TaskItemReceivedCallback(UUID itemID, UUID folderID, UUID creatorID, - UUID assetID, InventoryType type); + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler ItemReceived + { + add { lock (m_ItemReceivedLock) { m_ItemReceived += value; } } + remove { lock (m_ItemReceivedLock) { m_ItemReceived -= value; } } + } - /// - /// - /// - /// - /// - public delegate void FindObjectByPathCallback(string path, UUID inventoryObjectID); - /// - /// Reply received after calling RequestTaskInventory, - /// contains a filename that can be used in an asset download request - /// - /// UUID of the inventory item - /// Version number of the task inventory asset - /// Filename of the task inventory asset - public delegate void TaskInventoryReplyCallback(UUID itemID, short serial, string assetFilename); + /// The event subscribers, null of no subscribers + private EventHandler m_FolderUpdated; + + ///Raises the FolderUpdated Event + /// A FolderUpdatedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnFolderUpdated(FolderUpdatedEventArgs e) + { + EventHandler handler = m_FolderUpdated; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FolderUpdatedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler FolderUpdated + { + add { lock (m_FolderUpdatedLock) { m_FolderUpdated += value; } } + remove { lock (m_FolderUpdatedLock) { m_FolderUpdated -= value; } } + } + + + /// The event subscribers, null of no subscribers + private EventHandler m_InventoryObjectOffered; + + ///Raises the InventoryObjectOffered Event + /// A InventoryObjectOfferedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnInventoryObjectOffered(InventoryObjectOfferedEventArgs e) + { + EventHandler handler = m_InventoryObjectOffered; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_InventoryObjectOfferedLock = new object(); + + /// Raised when the simulator sends us data containing + /// an inventory object sent by another avatar or primitive + public event EventHandler InventoryObjectOffered + { + add { lock (m_InventoryObjectOfferedLock) { m_InventoryObjectOffered += value; } } + remove { lock (m_InventoryObjectOfferedLock) { m_InventoryObjectOffered -= value; } } + } + + /// The event subscribers, null of no subscribers + private EventHandler m_TaskItemReceived; + + ///Raises the TaskItemReceived Event + /// A TaskItemReceivedEventArgs object containing + /// the data sent from the simulator + protected virtual void OnTaskItemReceived(TaskItemReceivedEventArgs e) + { + EventHandler handler = m_TaskItemReceived; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TaskItemReceivedLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler TaskItemReceived + { + add { lock (m_TaskItemReceivedLock) { m_TaskItemReceived += value; } } + remove { lock (m_TaskItemReceivedLock) { m_TaskItemReceived -= value; } } + } + + + /// The event subscribers, null of no subscribers + private EventHandler m_FindObjectByPathReply; + + ///Raises the FindObjectByPath Event + /// A FindObjectByPathEventArgs object containing + /// the data sent from the simulator + protected virtual void OnFindObjectByPathReply(FindObjectByPathReplyEventArgs e) + { + EventHandler handler = m_FindObjectByPathReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_FindObjectByPathReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler FindObjectByPathReply + { + add { lock (m_FindObjectByPathReplyLock) { m_FindObjectByPathReply += value; } } + remove { lock (m_FindObjectByPathReplyLock) { m_FindObjectByPathReply -= value; } } + } + + + /// The event subscribers, null of no subscribers + private EventHandler m_TaskInventoryReply; + + ///Raises the TaskInventoryReply Event + /// A TaskInventoryReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnTaskInventoryReply(TaskInventoryReplyEventArgs e) + { + EventHandler handler = m_TaskInventoryReply; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_TaskInventoryReplyLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler TaskInventoryReply + { + add { lock (m_TaskInventoryReplyLock) { m_TaskInventoryReply += value; } } + remove { lock (m_TaskInventoryReplyLock) { m_TaskInventoryReply -= value; } } + } /// /// Reply received when uploading an inventory asset @@ -925,12 +1047,30 @@ namespace OpenMetaverse /// New asset UUID public delegate void InventoryUploadedAssetCallback(bool success, string status, UUID itemID, UUID assetID); - /// - /// Fired when local inventory store needs to be updated. Generally at logout to update a local cache - /// - /// the assets UUID - /// The new AssetID of the item, or UUID.Zero - public delegate void SaveAssetToInventoryCallback(UUID itemID, UUID newAssetID); + + /// The event subscribers, null of no subscribers + private EventHandler m_SaveAssetToInventory; + + ///Raises the SaveAssetToInventory Event + /// A SaveAssetToInventoryEventArgs object containing + /// the data sent from the simulator + protected virtual void OnSaveAssetToInventory(SaveAssetToInventoryEventArgs e) + { + EventHandler handler = m_SaveAssetToInventory; + if (handler != null) + handler(this, e); + } + + /// Thread sync lock object + private readonly object m_SaveAssetToInventoryLock = new object(); + + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler SaveAssetToInventory + { + add { lock (m_SaveAssetToInventoryLock) { m_SaveAssetToInventory += value; } } + remove { lock (m_SaveAssetToInventoryLock) { m_SaveAssetToInventory -= value; } } + } /// /// @@ -940,68 +1080,31 @@ namespace OpenMetaverse /// /// public delegate void ScriptUpdatedCallback(bool success, string status, UUID itemID, UUID assetID); + + /// The event subscribers, null of no subscribers + private EventHandler m_ScriptRunningReply; - /// - /// - /// - /// - /// - /// - /// - public delegate void ScriptRunningCallback(UUID objectID, UUID sctriptID, bool isMono, bool isRunning); - #endregion Delegates + ///Raises the ScriptRunningReply Event + /// A ScriptRunningReplyEventArgs object containing + /// the data sent from the simulator + protected virtual void OnScriptRunningReply(ScriptRunningReplyEventArgs e) + { + EventHandler handler = m_ScriptRunningReply; + if (handler != null) + handler(this, e); + } - #region Events + /// Thread sync lock object + private readonly object m_ScriptRunningReplyLock = new object(); - /// - /// Fired when a reply to a RequestFetchInventory() is received - /// - /// - public event ItemReceivedCallback OnItemReceived; - - /// - /// Fired when a response to a RequestFolderContents() is received - /// - /// - public event FolderUpdatedCallback OnFolderUpdated; - - /// - /// Fired when an object or another avatar offers us an inventory item - /// - public event ObjectOfferedCallback OnObjectOffered; - - /// - /// Fired when a response to FindObjectByPath() is received - /// - /// - public event FindObjectByPathCallback OnFindObjectByPath; - - /// - /// Fired when a task inventory item is received - /// - /// This may occur when an object that's rezzed in world is - /// taken into inventory, when an item is created using the CreateInventoryItem - /// packet, or when an object is purchased - /// - public event TaskItemReceivedCallback OnTaskItemReceived; - - /// - /// Fired in response to a request for a tasks (primitive) inventory - /// - /// - /// - public event TaskInventoryReplyCallback OnTaskInventoryReply; - - /// - /// Fired when a SaveAssetToInventory packet is received, generally after the logout reply handler - /// - public event SaveAssetToInventoryCallback OnSaveAssetToInventory; - - /// - /// Fired in response to a GetScriptRunning request - /// - public event ScriptRunningCallback OnScriptRunning; - #endregion Events + /// Raised when the simulator sends us data containing + /// ... + public event EventHandler ScriptRunningReply + { + add { lock (m_ScriptRunningReplyLock) { m_ScriptRunningReply += value; } } + remove { lock (m_ScriptRunningReplyLock) { m_ScriptRunningReply -= value; } } + } + #endregion Delegates #region String Arrays @@ -1034,13 +1137,13 @@ namespace OpenMetaverse #endregion String Arrays - private GridClient _Client; + private GridClient Client; private Inventory _Store; //private Random _RandNumbers = new Random(); private object _CallbacksLock = new object(); private uint _CallbackPos; private Dictionary _ItemCreatedCallbacks = new Dictionary(); - private Dictionary _ItemCopiedCallbacks = new Dictionary(); + private Dictionary _ItemCopiedCallbacks = new Dictionary(); private List _Searches = new List(); #region Properties @@ -1058,22 +1161,22 @@ namespace OpenMetaverse /// Reference to the GridClient object public InventoryManager(GridClient client) { - _Client = client; + Client = client; - _Client.Network.RegisterCallback(PacketType.UpdateCreateInventoryItem, UpdateCreateInventoryItemHandler); - _Client.Network.RegisterCallback(PacketType.SaveAssetIntoInventory, SaveAssetIntoInventoryHandler); - _Client.Network.RegisterCallback(PacketType.BulkUpdateInventory, BulkUpdateInventoryHandler); - _Client.Network.RegisterCallback(PacketType.MoveInventoryItem, MoveInventoryItemHandler); - _Client.Network.RegisterCallback(PacketType.InventoryDescendents, InventoryDescendentsHandler); - _Client.Network.RegisterCallback(PacketType.FetchInventoryReply, FetchInventoryReplyHandler); - _Client.Network.RegisterCallback(PacketType.ReplyTaskInventory, ReplyTaskInventoryHandler); - _Client.Network.RegisterEventCallback("ScriptRunningReply", new Caps.EventQueueCallback(ScriptRunningReplyMessageHandler)); + Client.Network.RegisterCallback(PacketType.UpdateCreateInventoryItem, UpdateCreateInventoryItemHandler); + Client.Network.RegisterCallback(PacketType.SaveAssetIntoInventory, SaveAssetIntoInventoryHandler); + Client.Network.RegisterCallback(PacketType.BulkUpdateInventory, BulkUpdateInventoryHandler); + Client.Network.RegisterCallback(PacketType.MoveInventoryItem, MoveInventoryItemHandler); + Client.Network.RegisterCallback(PacketType.InventoryDescendents, InventoryDescendentsHandler); + Client.Network.RegisterCallback(PacketType.FetchInventoryReply, FetchInventoryReplyHandler); + Client.Network.RegisterCallback(PacketType.ReplyTaskInventory, ReplyTaskInventoryHandler); + Client.Network.RegisterEventCallback("ScriptRunningReply", new Caps.EventQueueCallback(ScriptRunningReplyMessageHandler)); // Watch for inventory given to us through instant message - _Client.Self.IM += Self_IM; + Client.Self.IM += Self_IM; // Register extra parameters with login and parse the inventory data that comes back - _Client.Network.RegisterLoginResponseCallback( + Client.Network.RegisterLoginResponseCallback( new NetworkManager.LoginResponseCallback(Network_OnLoginResponse), new string[] { "inventory-root", "inventory-skeleton", "inventory-lib-root", @@ -1096,21 +1199,21 @@ namespace OpenMetaverse AutoResetEvent fetchEvent = new AutoResetEvent(false); InventoryItem fetchedItem = null; - ItemReceivedCallback callback = - delegate(InventoryItem item) + EventHandler callback = + delegate(object sender, ItemReceivedEventArgs e) { - if (item.UUID == itemID) + if (e.Item.UUID == itemID) { - fetchedItem = item; + fetchedItem = e.Item; fetchEvent.Set(); } }; - OnItemReceived += callback; + ItemReceived += callback; RequestFetchInventory(itemID, ownerID); fetchEvent.WaitOne(timeoutMS, false); - OnItemReceived -= callback; + ItemReceived -= callback; return fetchedItem; } @@ -1125,15 +1228,15 @@ namespace OpenMetaverse { FetchInventoryPacket fetch = new FetchInventoryPacket(); fetch.AgentData = new FetchInventoryPacket.AgentDataBlock(); - fetch.AgentData.AgentID = _Client.Self.AgentID; - fetch.AgentData.SessionID = _Client.Self.SessionID; + fetch.AgentData.AgentID = Client.Self.AgentID; + fetch.AgentData.SessionID = Client.Self.SessionID; fetch.InventoryData = new FetchInventoryPacket.InventoryDataBlock[1]; fetch.InventoryData[0] = new FetchInventoryPacket.InventoryDataBlock(); fetch.InventoryData[0].ItemID = itemID; fetch.InventoryData[0].OwnerID = ownerID; - _Client.Network.SendPacket(fetch); + Client.Network.SendPacket(fetch); } /// @@ -1149,8 +1252,8 @@ namespace OpenMetaverse FetchInventoryPacket fetch = new FetchInventoryPacket(); fetch.AgentData = new FetchInventoryPacket.AgentDataBlock(); - fetch.AgentData.AgentID = _Client.Self.AgentID; - fetch.AgentData.SessionID = _Client.Self.SessionID; + fetch.AgentData.AgentID = Client.Self.AgentID; + fetch.AgentData.SessionID = Client.Self.SessionID; fetch.InventoryData = new FetchInventoryPacket.InventoryDataBlock[itemIDs.Count]; for (int i = 0; i < itemIDs.Count; i++) @@ -1160,7 +1263,7 @@ namespace OpenMetaverse fetch.InventoryData[i].OwnerID = ownerIDs[i]; } - _Client.Network.SendPacket(fetch); + Client.Network.SendPacket(fetch); } /// @@ -1182,16 +1285,16 @@ namespace OpenMetaverse List objects = null; AutoResetEvent fetchEvent = new AutoResetEvent(false); - FolderUpdatedCallback callback = - delegate(UUID folderID) + EventHandler callback = + delegate(object sender, FolderUpdatedEventArgs e) { - if (folderID == folder + if (e.FolderID == folder && _Store[folder] is InventoryFolder) { // InventoryDescendentsHandler only stores DescendendCount if both folders and items are fetched. if (_Store.GetContents(folder).Count >= ((InventoryFolder)_Store[folder]).DescendentCount) { - + fetchEvent.Set(); } } @@ -1201,13 +1304,13 @@ namespace OpenMetaverse } }; - OnFolderUpdated += callback; + FolderUpdated += callback; RequestFolderContents(folder, owner, folders, items, order); if (fetchEvent.WaitOne(timeoutMS, false)) objects = _Store.GetContents(folder); - OnFolderUpdated -= callback; + FolderUpdated -= callback; return objects; } @@ -1221,12 +1324,12 @@ namespace OpenMetaverse /// true to return s containd in folder /// the sort order to return items in /// - public void RequestFolderContents(UUID folder, UUID owner, bool folders, bool items, + public void RequestFolderContents(UUID folder, UUID owner, bool folders, bool items, InventorySortOrder order) { FetchInventoryDescendentsPacket fetch = new FetchInventoryDescendentsPacket(); - fetch.AgentData.AgentID = _Client.Self.AgentID; - fetch.AgentData.SessionID = _Client.Self.SessionID; + fetch.AgentData.AgentID = Client.Self.AgentID; + fetch.AgentData.SessionID = Client.Self.SessionID; fetch.InventoryData.FetchFolders = folders; fetch.InventoryData.FetchItems = items; @@ -1234,7 +1337,7 @@ namespace OpenMetaverse fetch.InventoryData.OwnerID = owner; fetch.InventoryData.SortOrder = (int)order; - _Client.Network.SendPacket(fetch); + Client.Network.SendPacket(fetch); } #endregion Fetch @@ -1255,7 +1358,7 @@ namespace OpenMetaverse if (_Store == null) { Logger.Log("Inventory is null, FindFolderForType() lookup cannot continue", - Helpers.LogLevel.Error, _Client); + Helpers.LogLevel.Error, Client); return UUID.Zero; } @@ -1295,22 +1398,22 @@ namespace OpenMetaverse AutoResetEvent findEvent = new AutoResetEvent(false); UUID foundItem = UUID.Zero; - FindObjectByPathCallback callback = - delegate(string thisPath, UUID inventoryObjectID) + EventHandler callback = + delegate(object sender, FindObjectByPathReplyEventArgs e) { - if (thisPath == path) + if (e.Path == path) { - foundItem = inventoryObjectID; + foundItem = e.InventoryObjectID; findEvent.Set(); } }; - OnFindObjectByPath += callback; + FindObjectByPathReply += callback; RequestFindObjectByPath(baseFolder, inventoryOwner, path); findEvent.WaitOne(timeoutMS, false); - OnFindObjectByPath -= callback; + FindObjectByPathReply -= callback; return foundItem; } @@ -1373,7 +1476,7 @@ namespace OpenMetaverse #endregion Find #region Move/Rename - + /// /// Move an inventory item or folder to a new location /// @@ -1421,8 +1524,8 @@ namespace OpenMetaverse } UpdateInventoryFolderPacket move = new UpdateInventoryFolderPacket(); - move.AgentData.AgentID = _Client.Self.AgentID; - move.AgentData.SessionID = _Client.Self.SessionID; + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; move.FolderData = new UpdateInventoryFolderPacket.FolderDataBlock[1]; move.FolderData[0] = new UpdateInventoryFolderPacket.FolderDataBlock(); move.FolderData[0].FolderID = folderID; @@ -1430,7 +1533,7 @@ namespace OpenMetaverse move.FolderData[0].Name = Utils.StringToBytes(newName); move.FolderData[0].Type = -1; - _Client.Network.SendPacket(move); + Client.Network.SendPacket(move); } /// @@ -1451,18 +1554,18 @@ namespace OpenMetaverse } MoveInventoryFolderPacket move = new MoveInventoryFolderPacket(); - move.AgentData.AgentID = _Client.Self.AgentID; - move.AgentData.SessionID = _Client.Self.SessionID; + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; move.AgentData.Stamp = false; //FIXME: ?? move.InventoryData = new MoveInventoryFolderPacket.InventoryDataBlock[1]; move.InventoryData[0] = new MoveInventoryFolderPacket.InventoryDataBlock(); move.InventoryData[0].FolderID = folderID; move.InventoryData[0].ParentID = newParentID; - - _Client.Network.SendPacket(move); + + Client.Network.SendPacket(move); } - + /// /// Move multiple folders, the keys in the Dictionary parameter, /// to a new parents, the value of that folder's key. @@ -1489,8 +1592,8 @@ namespace OpenMetaverse //TODO: Test if this truly supports multiple-folder move MoveInventoryFolderPacket move = new MoveInventoryFolderPacket(); - move.AgentData.AgentID = _Client.Self.AgentID; - move.AgentData.SessionID = _Client.Self.SessionID; + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; move.AgentData.Stamp = false; //FIXME: ?? move.InventoryData = new MoveInventoryFolderPacket.InventoryDataBlock[foldersNewParents.Count]; @@ -1504,7 +1607,7 @@ namespace OpenMetaverse move.InventoryData[index++] = block; } - _Client.Network.SendPacket(move); + Client.Network.SendPacket(move); } @@ -1528,18 +1631,18 @@ namespace OpenMetaverse { lock (_Store) { - if (_Store.Contains(itemID)) - { - InventoryBase inv = _Store[itemID]; - inv.Name = newName; - inv.ParentUUID = folderID; - _Store.UpdateNodeFor(inv); - } + if (_Store.Contains(itemID)) + { + InventoryBase inv = _Store[itemID]; + inv.Name = newName; + inv.ParentUUID = folderID; + _Store.UpdateNodeFor(inv); + } } MoveInventoryItemPacket move = new MoveInventoryItemPacket(); - move.AgentData.AgentID = _Client.Self.AgentID; - move.AgentData.SessionID = _Client.Self.SessionID; + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; move.AgentData.Stamp = false; //FIXME: ?? move.InventoryData = new MoveInventoryItemPacket.InventoryDataBlock[1]; @@ -1548,7 +1651,7 @@ namespace OpenMetaverse move.InventoryData[0].FolderID = folderID; move.InventoryData[0].NewName = Utils.StringToBytes(newName); - _Client.Network.SendPacket(move); + Client.Network.SendPacket(move); } /// @@ -1573,8 +1676,8 @@ namespace OpenMetaverse } MoveInventoryItemPacket move = new MoveInventoryItemPacket(); - move.AgentData.AgentID = _Client.Self.AgentID; - move.AgentData.SessionID = _Client.Self.SessionID; + move.AgentData.AgentID = Client.Self.AgentID; + move.AgentData.SessionID = Client.Self.SessionID; move.AgentData.Stamp = false; //FIXME: ?? move.InventoryData = new MoveInventoryItemPacket.InventoryDataBlock[itemsNewParents.Count]; @@ -1589,7 +1692,7 @@ namespace OpenMetaverse move.InventoryData[index++] = block; } - _Client.Network.SendPacket(move); + Client.Network.SendPacket(move); } #endregion Move @@ -1603,10 +1706,10 @@ namespace OpenMetaverse public void RemoveDescendants(UUID folder) { PurgeInventoryDescendentsPacket purge = new PurgeInventoryDescendentsPacket(); - purge.AgentData.AgentID = _Client.Self.AgentID; - purge.AgentData.SessionID = _Client.Self.SessionID; + purge.AgentData.AgentID = Client.Self.AgentID; + purge.AgentData.SessionID = Client.Self.SessionID; purge.InventoryData.FolderID = folder; - _Client.Network.SendPacket(purge); + Client.Network.SendPacket(purge); // Update our local copy lock (_Store) @@ -1657,8 +1760,8 @@ namespace OpenMetaverse return; RemoveInventoryObjectsPacket rem = new RemoveInventoryObjectsPacket(); - rem.AgentData.AgentID = _Client.Self.AgentID; - rem.AgentData.SessionID = _Client.Self.SessionID; + rem.AgentData.AgentID = Client.Self.AgentID; + rem.AgentData.SessionID = Client.Self.SessionID; if (items == null || items.Count == 0) { @@ -1707,9 +1810,9 @@ namespace OpenMetaverse } } } - _Client.Network.SendPacket(rem); + Client.Network.SendPacket(rem); } - + /// /// Empty the Lost and Found folder /// @@ -1758,11 +1861,11 @@ namespace OpenMetaverse } } Remove(remItems, remFolders); - } + } #endregion Remove #region Create - + /// /// /// @@ -1778,7 +1881,7 @@ namespace OpenMetaverse InventoryType invType, PermissionMask nextOwnerMask, ItemCreatedCallback callback) { // Even though WearableType 0 is Shape, in this context it is treated as NOT_WEARABLE - RequestCreateItem(parentFolder, name, description, type, assetTransactionID, invType, (WearableType)0, nextOwnerMask, + RequestCreateItem(parentFolder, name, description, type, assetTransactionID, invType, (WearableType)0, nextOwnerMask, callback); } @@ -1798,8 +1901,8 @@ namespace OpenMetaverse InventoryType invType, WearableType wearableType, PermissionMask nextOwnerMask, ItemCreatedCallback callback) { CreateInventoryItemPacket create = new CreateInventoryItemPacket(); - create.AgentData.AgentID = _Client.Self.AgentID; - create.AgentData.SessionID = _Client.Self.SessionID; + create.AgentData.AgentID = Client.Self.AgentID; + create.AgentData.SessionID = Client.Self.SessionID; create.InventoryBlock.CallbackID = RegisterItemCreatedCallback(callback); create.InventoryBlock.FolderID = parentFolder; @@ -1811,7 +1914,7 @@ namespace OpenMetaverse create.InventoryBlock.Name = Utils.StringToBytes(name); create.InventoryBlock.Description = Utils.StringToBytes(description); - _Client.Network.SendPacket(create); + Client.Network.SendPacket(create); } /// @@ -1862,23 +1965,23 @@ namespace OpenMetaverse newFolder.ParentUUID = parentID; newFolder.PreferredType = preferredType; newFolder.Name = name; - newFolder.OwnerID = _Client.Self.AgentID; + newFolder.OwnerID = Client.Self.AgentID; // Update the local store try { _Store[newFolder.UUID] = newFolder; } - catch (InventoryException ie) { Logger.Log(ie.Message, Helpers.LogLevel.Warning, _Client, ie); } + catch (InventoryException ie) { Logger.Log(ie.Message, Helpers.LogLevel.Warning, Client, ie); } // Create the create folder packet and send it CreateInventoryFolderPacket create = new CreateInventoryFolderPacket(); - create.AgentData.AgentID = _Client.Self.AgentID; - create.AgentData.SessionID = _Client.Self.SessionID; + create.AgentData.AgentID = Client.Self.AgentID; + create.AgentData.SessionID = Client.Self.SessionID; create.FolderData.FolderID = id; create.FolderData.ParentID = parentID; create.FolderData.Type = (sbyte)preferredType; create.FolderData.Name = Utils.StringToBytes(name); - _Client.Network.SendPacket(create); + Client.Network.SendPacket(create); return id; } @@ -1919,10 +2022,10 @@ namespace OpenMetaverse public void RequestCreateItemFromAsset(byte[] data, string name, string description, AssetType assetType, InventoryType invType, UUID folderID, Permissions permissions, ItemCreatedFromAssetCallback callback) { - if (_Client.Network.CurrentSim == null || _Client.Network.CurrentSim.Caps == null) + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) throw new Exception("NewFileAgentInventory capability is not currently available"); - Uri url = _Client.Network.CurrentSim.Caps.CapabilityURI("NewFileAgentInventory"); + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("NewFileAgentInventory"); if (url != null) { @@ -1935,14 +2038,14 @@ namespace OpenMetaverse query.Add("everyone_mask", OSD.FromInteger((int)permissions.EveryoneMask)); query.Add("group_mask", OSD.FromInteger((int)permissions.GroupMask)); query.Add("next_owner_mask", OSD.FromInteger((int)permissions.NextOwnerMask)); - query.Add("expected_upload_cost", OSD.FromInteger(_Client.Settings.UPLOAD_COST)); + query.Add("expected_upload_cost", OSD.FromInteger(Client.Settings.UPLOAD_COST)); // Make the request CapsClient request = new CapsClient(url); request.OnComplete += CreateItemFromAssetResponse; - request.UserData = new object[] { callback, data, _Client.Settings.CAPS_TIMEOUT, query }; + request.UserData = new object[] { callback, data, Client.Settings.CAPS_TIMEOUT, query }; - request.BeginGetResponse(query, OSDFormat.Xml, _Client.Settings.CAPS_TIMEOUT); + request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -1963,7 +2066,7 @@ namespace OpenMetaverse /// public void RequestCopyItem(UUID item, UUID newParent, string newName, ItemCopiedCallback callback) { - RequestCopyItem(item, newParent, newName, _Client.Self.AgentID, callback); + RequestCopyItem(item, newParent, newName, Client.Self.AgentID, callback); } /// @@ -2006,8 +2109,8 @@ namespace OpenMetaverse uint callbackID = RegisterItemsCopiedCallback(callback); CopyInventoryItemPacket copy = new CopyInventoryItemPacket(); - copy.AgentData.AgentID = _Client.Self.AgentID; - copy.AgentData.SessionID = _Client.Self.SessionID; + copy.AgentData.AgentID = Client.Self.AgentID; + copy.AgentData.SessionID = Client.Self.SessionID; copy.InventoryData = new CopyInventoryItemPacket.InventoryDataBlock[items.Count]; for (int i = 0; i < items.Count; ++i) @@ -2024,7 +2127,7 @@ namespace OpenMetaverse copy.InventoryData[i].NewName = Utils.EmptyBytes; } - _Client.Network.SendPacket(copy); + Client.Network.SendPacket(copy); } /// @@ -2039,7 +2142,7 @@ namespace OpenMetaverse { _ItemCopiedCallbacks[0] = callback; //Notecards always use callback ID 0 - Uri url = _Client.Network.CurrentSim.Caps.CapabilityURI("CopyInventoryFromNotecard"); + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("CopyInventoryFromNotecard"); if (url != null) { @@ -2051,13 +2154,13 @@ namespace OpenMetaverse message.ObjectID = objectID; CapsClient request = new CapsClient(url); - request.BeginGetResponse(message.Serialize(), OSDFormat.Xml, _Client.Settings.CAPS_TIMEOUT); + request.BeginGetResponse(message.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { CopyInventoryFromNotecardPacket copy = new CopyInventoryFromNotecardPacket(); - copy.AgentData.AgentID = _Client.Self.AgentID; - copy.AgentData.SessionID = _Client.Self.SessionID; + copy.AgentData.AgentID = Client.Self.AgentID; + copy.AgentData.SessionID = Client.Self.SessionID; copy.NotecardData.ObjectID = objectID; copy.NotecardData.NotecardItemID = notecardID; @@ -2067,7 +2170,7 @@ namespace OpenMetaverse copy.InventoryData[0].FolderID = folderID; copy.InventoryData[0].ItemID = itemID; - _Client.Network.SendPacket(copy); + Client.Network.SendPacket(copy); } } @@ -2104,8 +2207,8 @@ namespace OpenMetaverse public void RequestUpdateItems(List items, UUID transactionID) { UpdateInventoryItemPacket update = new UpdateInventoryItemPacket(); - update.AgentData.AgentID = _Client.Self.AgentID; - update.AgentData.SessionID = _Client.Self.SessionID; + update.AgentData.AgentID = Client.Self.AgentID; + update.AgentData.SessionID = Client.Self.SessionID; update.AgentData.TransactionID = transactionID; update.InventoryData = new UpdateInventoryItemPacket.InventoryDataBlock[items.Count]; @@ -2139,7 +2242,7 @@ namespace OpenMetaverse update.InventoryData[i] = block; } - _Client.Network.SendPacket(update); + Client.Network.SendPacket(update); } /// @@ -2150,10 +2253,10 @@ namespace OpenMetaverse /// public void RequestUploadNotecardAsset(byte[] data, UUID notecardID, InventoryUploadedAssetCallback callback) { - if (_Client.Network.CurrentSim == null || _Client.Network.CurrentSim.Caps == null) + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) throw new Exception("UpdateNotecardAgentInventory capability is not currently available"); - Uri url = _Client.Network.CurrentSim.Caps.CapabilityURI("UpdateNotecardAgentInventory"); + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateNotecardAgentInventory"); if (url != null) { @@ -2164,7 +2267,7 @@ namespace OpenMetaverse CapsClient request = new CapsClient(url); request.OnComplete += UploadInventoryAssetResponse; request.UserData = new object[] { new KeyValuePair(callback, data), notecardID }; - request.BeginGetResponse(query, OSDFormat.Xml, _Client.Settings.CAPS_TIMEOUT); + request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2180,10 +2283,10 @@ namespace OpenMetaverse /// Callback whick will be called when upload is complete public void RequestUploadGestureAsset(byte[] data, UUID gestureID, InventoryUploadedAssetCallback callback) { - if (_Client.Network.CurrentSim == null || _Client.Network.CurrentSim.Caps == null) + if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null) throw new Exception("UpdateGestureAgentInventory capability is not currently available"); - Uri url = _Client.Network.CurrentSim.Caps.CapabilityURI("UpdateGestureAgentInventory"); + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateGestureAgentInventory"); if (url != null) { @@ -2194,7 +2297,7 @@ namespace OpenMetaverse CapsClient request = new CapsClient(url); request.OnComplete += UploadInventoryAssetResponse; request.UserData = new object[] { new KeyValuePair(callback, data), gestureID }; - request.BeginGetResponse(query, OSDFormat.Xml, _Client.Settings.CAPS_TIMEOUT); + request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2211,18 +2314,18 @@ namespace OpenMetaverse /// public void RequestUpdateScriptAgentInventory(byte[] data, UUID itemID, bool mono, ScriptUpdatedCallback callback) { - Uri url = _Client.Network.CurrentSim.Caps.CapabilityURI("UpdateScriptAgent"); + Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateScriptAgent"); - if(url != null) + if (url != null) { UpdateScriptAgentRequestMessage msg = new UpdateScriptAgentRequestMessage(); msg.ItemID = itemID; msg.Target = mono ? "mono" : "lsl2"; - + CapsClient request = new CapsClient(url); request.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse); request.UserData = new object[2] { new KeyValuePair(callback, data), itemID }; - request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, _Client.Settings.CAPS_TIMEOUT); + request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT); } else { @@ -2244,7 +2347,7 @@ namespace OpenMetaverse public UUID RequestRezFromInventory(Simulator simulator, Quaternion rotation, Vector3 position, InventoryItem item) { - return RequestRezFromInventory(simulator, rotation, position, item, _Client.Self.ActiveGroup, + return RequestRezFromInventory(simulator, rotation, position, item, Client.Self.ActiveGroup, UUID.Random(), true); } @@ -2278,8 +2381,8 @@ namespace OpenMetaverse { RezObjectPacket add = new RezObjectPacket(); - add.AgentData.AgentID = _Client.Self.AgentID; - add.AgentData.SessionID = _Client.Self.SessionID; + add.AgentData.AgentID = Client.Self.AgentID; + add.AgentData.SessionID = Client.Self.SessionID; add.AgentData.GroupID = groupOwner; add.RezData.FromTaskID = UUID.Zero; @@ -2316,7 +2419,7 @@ namespace OpenMetaverse add.InventoryData.Description = Utils.StringToBytes(item.Description); add.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); - _Client.Network.SendPacket(add, simulator); + Client.Network.SendPacket(add, simulator); return queryID; } @@ -2327,8 +2430,8 @@ namespace OpenMetaverse /// The simulator Local ID of the object public void RequestDeRezToInventory(uint objectLocalID) { - RequestDeRezToInventory(objectLocalID, DeRezDestination.AgentInventoryTake, - _Client.Inventory.FindFolderForType(AssetType.Object), UUID.Random()); + RequestDeRezToInventory(objectLocalID, DeRezDestination.AgentInventoryTake, + Client.Inventory.FindFolderForType(AssetType.Object), UUID.Random()); } /// @@ -2344,8 +2447,8 @@ namespace OpenMetaverse { DeRezObjectPacket take = new DeRezObjectPacket(); - take.AgentData.AgentID = _Client.Self.AgentID; - take.AgentData.SessionID = _Client.Self.SessionID; + take.AgentData.AgentID = Client.Self.AgentID; + take.AgentData.SessionID = Client.Self.SessionID; take.AgentBlock = new DeRezObjectPacket.AgentBlockBlock(); take.AgentBlock.GroupID = UUID.Zero; take.AgentBlock.Destination = (byte)destType; @@ -2357,10 +2460,10 @@ namespace OpenMetaverse take.ObjectData = new DeRezObjectPacket.ObjectDataBlock[1]; take.ObjectData[0] = new DeRezObjectPacket.ObjectDataBlock(); take.ObjectData[0].ObjectLocalID = objectLocalID; - - _Client.Network.SendPacket(take); + + Client.Network.SendPacket(take); } - + /// /// Rez an item from inventory to its previous simulator location /// @@ -2372,8 +2475,8 @@ namespace OpenMetaverse { RezRestoreToWorldPacket add = new RezRestoreToWorldPacket(); - add.AgentData.AgentID = _Client.Self.AgentID; - add.AgentData.SessionID = _Client.Self.SessionID; + add.AgentData.AgentID = Client.Self.AgentID; + add.AgentData.SessionID = Client.Self.SessionID; add.InventoryData.ItemID = item.UUID; add.InventoryData.FolderID = item.ParentUUID; @@ -2396,7 +2499,7 @@ namespace OpenMetaverse add.InventoryData.Description = Utils.StringToBytes(item.Description); add.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); - _Client.Network.SendPacket(add, simulator); + Client.Network.SendPacket(add, simulator); return queryID; } @@ -2415,25 +2518,25 @@ namespace OpenMetaverse byte[] bucket; - bucket = new byte[17]; - bucket[0] = (byte)assetType; - Buffer.BlockCopy(itemID.GetBytes(), 0, bucket, 1, 16); + bucket = new byte[17]; + bucket[0] = (byte)assetType; + Buffer.BlockCopy(itemID.GetBytes(), 0, bucket, 1, 16); - _Client.Self.InstantMessage( - _Client.Self.Name, + Client.Self.InstantMessage( + Client.Self.Name, recipient, itemName, UUID.Random(), InstantMessageDialog.InventoryOffered, InstantMessageOnline.Online, - _Client.Self.SimPosition, - _Client.Network.CurrentSim.ID, + Client.Self.SimPosition, + Client.Network.CurrentSim.ID, bucket); if (doEffect) { - _Client.Self.BeamEffect(_Client.Self.AgentID, recipient, Vector3d.Zero, - _Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random()); + Client.Self.BeamEffect(Client.Self.AgentID, recipient, Vector3d.Zero, + Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random()); } } @@ -2450,41 +2553,41 @@ namespace OpenMetaverse { byte[] bucket; - List folderContents = new List(); + List folderContents = new List(); - _Client.Inventory.FolderContents(folderID, _Client.Self.AgentID, false, true, InventorySortOrder.ByDate, 1000 * 15).ForEach( - delegate(InventoryBase ib) - { - folderContents.Add(_Client.Inventory.FetchItem(ib.UUID, _Client.Self.AgentID, 1000 * 10)); - }); - bucket = new byte[17 * (folderContents.Count + 1)]; - - //Add parent folder (first item in bucket) - bucket[0] = (byte)assetType; - Buffer.BlockCopy(folderID.GetBytes(), 0, bucket, 1, 16); - - //Add contents to bucket after folder - for (int i = 1; i <= folderContents.Count; ++i) + Client.Inventory.FolderContents(folderID, Client.Self.AgentID, false, true, InventorySortOrder.ByDate, 1000 * 15).ForEach( + delegate(InventoryBase ib) { - bucket[i * 17] = (byte)folderContents[i - 1].AssetType; - Buffer.BlockCopy(folderContents[i - 1].UUID.GetBytes(), 0, bucket, i * 17 + 1, 16); - } + folderContents.Add(Client.Inventory.FetchItem(ib.UUID, Client.Self.AgentID, 1000 * 10)); + }); + bucket = new byte[17 * (folderContents.Count + 1)]; - _Client.Self.InstantMessage( - _Client.Self.Name, + //Add parent folder (first item in bucket) + bucket[0] = (byte)assetType; + Buffer.BlockCopy(folderID.GetBytes(), 0, bucket, 1, 16); + + //Add contents to bucket after folder + for (int i = 1; i <= folderContents.Count; ++i) + { + bucket[i * 17] = (byte)folderContents[i - 1].AssetType; + Buffer.BlockCopy(folderContents[i - 1].UUID.GetBytes(), 0, bucket, i * 17 + 1, 16); + } + + Client.Self.InstantMessage( + Client.Self.Name, recipient, folderName, UUID.Random(), InstantMessageDialog.InventoryOffered, InstantMessageOnline.Online, - _Client.Self.SimPosition, - _Client.Network.CurrentSim.ID, + Client.Self.SimPosition, + Client.Network.CurrentSim.ID, bucket); if (doEffect) { - _Client.Self.BeamEffect(_Client.Self.AgentID, recipient, Vector3d.Zero, - _Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random()); + Client.Self.BeamEffect(Client.Self.AgentID, recipient, Vector3d.Zero, + Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random()); } } @@ -2493,18 +2596,21 @@ namespace OpenMetaverse #region Task /// - /// + /// Copy or move an from agent inventory to a task (primitive) inventory /// - /// - /// + /// The target object + /// The item to copy or move from inventory /// + /// For items with copy permissions a copy of the item is placed in the tasks inventory, + /// for no-copy items the object is moved to the tasks inventory + // DocTODO: what does the return UUID correlate to if anything? public UUID UpdateTaskInventory(uint objectLocalID, InventoryItem item) { UUID transactionID = UUID.Random(); UpdateTaskInventoryPacket update = new UpdateTaskInventoryPacket(); - update.AgentData.AgentID = _Client.Self.AgentID; - update.AgentData.SessionID = _Client.Self.SessionID; + update.AgentData.AgentID = Client.Self.AgentID; + update.AgentData.SessionID = Client.Self.SessionID; update.UpdateData.Key = 0; update.UpdateData.LocalID = objectLocalID; @@ -2530,40 +2636,43 @@ namespace OpenMetaverse update.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); update.InventoryData.CRC = ItemCRC(item); - _Client.Network.SendPacket(update); + Client.Network.SendPacket(update); return transactionID; } /// - /// Get the inventory of a Task (Primitive) + /// Retrieve a listing of the items contained in a task (Primitive) /// /// The tasks /// The tasks simulator local ID /// milliseconds to wait for reply from simulator - /// A List containing the inventory items inside the task - public List GetTaskInventory(UUID objectID, uint objectLocalID, int timeoutMS) + /// A list containing the inventory items inside the task or null + /// if a timeout occurs + /// This request blocks until the response from the simulator arrives + /// or timeoutMS is exceeded + public List GetTaskInventory(UUID objectID, UInt32 objectLocalID, Int32 timeoutMS) { - string filename = null; + String filename = null; AutoResetEvent taskReplyEvent = new AutoResetEvent(false); - TaskInventoryReplyCallback callback = - delegate(UUID itemID, short serial, string assetFilename) + EventHandler callback = + delegate(object sender, TaskInventoryReplyEventArgs e) { - if (itemID == objectID) + if (e.ItemID == objectID) { - filename = assetFilename; + filename = e.AssetFilename; taskReplyEvent.Set(); } }; - OnTaskInventoryReply += callback; + TaskInventoryReply += callback; RequestTaskInventory(objectLocalID); if (taskReplyEvent.WaitOne(timeoutMS, false)) { - OnTaskInventoryReply -= callback; + TaskInventoryReply -= callback; if (!String.IsNullOrEmpty(filename)) { @@ -2581,46 +2690,48 @@ namespace OpenMetaverse } }; - _Client.Assets.OnXferReceived += xferCallback; + Client.Assets.OnXferReceived += xferCallback; // Start the actual asset xfer - xferID = _Client.Assets.RequestAssetXfer(filename, true, false, UUID.Zero, AssetType.Unknown, true); + xferID = Client.Assets.RequestAssetXfer(filename, true, false, UUID.Zero, AssetType.Unknown, true); if (taskDownloadEvent.WaitOne(timeoutMS, false)) { - _Client.Assets.OnXferReceived -= xferCallback; + Client.Assets.OnXferReceived -= xferCallback; - string taskList = Utils.BytesToString(assetData); + String taskList = Utils.BytesToString(assetData); return ParseTaskInventory(taskList); } else { - Logger.Log("Timed out waiting for task inventory download for " + filename, Helpers.LogLevel.Warning, _Client); - _Client.Assets.OnXferReceived -= xferCallback; + Logger.Log("Timed out waiting for task inventory download for " + filename, Helpers.LogLevel.Warning, Client); + Client.Assets.OnXferReceived -= xferCallback; return null; } } else { - Logger.DebugLog("Task is empty for " + objectLocalID, _Client); - return null; + Logger.DebugLog("Task is empty for " + objectLocalID, Client); + return new List(0); } } else { - Logger.Log("Timed out waiting for task inventory reply for " + objectLocalID, Helpers.LogLevel.Warning, _Client); - OnTaskInventoryReply -= callback; + Logger.Log("Timed out waiting for task inventory reply for " + objectLocalID, Helpers.LogLevel.Warning, Client); + TaskInventoryReply -= callback; return null; } } /// - /// + /// Request the contents of a tasks (primitives) inventory from the + /// current simulator /// - /// + /// The LocalID of the object + /// public void RequestTaskInventory(uint objectLocalID) { - RequestTaskInventory(objectLocalID, _Client.Network.CurrentSim); + RequestTaskInventory(objectLocalID, Client.Network.CurrentSim); } /// @@ -2628,53 +2739,58 @@ namespace OpenMetaverse /// /// The simulator Local ID of the object /// A reference to the simulator object that contains the object + /// public void RequestTaskInventory(uint objectLocalID, Simulator simulator) { RequestTaskInventoryPacket request = new RequestTaskInventoryPacket(); - request.AgentData.AgentID = _Client.Self.AgentID; - request.AgentData.SessionID = _Client.Self.SessionID; + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; request.InventoryData.LocalID = objectLocalID; - _Client.Network.SendPacket(request, simulator); + Client.Network.SendPacket(request, simulator); } - + /// - /// Moves an Item from an objects (Prim) Inventory to the specified folder in the avatars inventory + /// Move an item from a tasks (Primitive) inventory to the specified folder in the avatars inventory /// /// LocalID of the object in the simulator /// UUID of the task item to move - /// UUID of the folder to move the item to + /// The ID of the destination folder in this agents inventory /// Simulator Object + /// Raises the event public void MoveTaskInventory(uint objectLocalID, UUID taskItemID, UUID inventoryFolderID, Simulator simulator) { MoveTaskInventoryPacket request = new MoveTaskInventoryPacket(); - request.AgentData.AgentID = _Client.Self.AgentID; - request.AgentData.SessionID = _Client.Self.SessionID; + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; request.AgentData.FolderID = inventoryFolderID; request.InventoryData.ItemID = taskItemID; request.InventoryData.LocalID = objectLocalID; - _Client.Network.SendPacket(request, simulator); + Client.Network.SendPacket(request, simulator); } - + /// /// Remove an item from an objects (Prim) Inventory /// /// LocalID of the object in the simulator /// UUID of the task item to remove /// Simulator Object + /// You can confirm the removal by comparing the tasks inventory serial before and after the + /// request with the request combined with + /// the event public void RemoveTaskInventory(uint objectLocalID, UUID taskItemID, Simulator simulator) { RemoveTaskInventoryPacket remove = new RemoveTaskInventoryPacket(); - remove.AgentData.AgentID = _Client.Self.AgentID; - remove.AgentData.SessionID = _Client.Self.SessionID; + remove.AgentData.AgentID = Client.Self.AgentID; + remove.AgentData.SessionID = Client.Self.SessionID; remove.InventoryData.ItemID = taskItemID; remove.InventoryData.LocalID = objectLocalID; - _Client.Network.SendPacket(remove, simulator); + Client.Network.SendPacket(remove, simulator); } /// @@ -2684,24 +2800,27 @@ namespace OpenMetaverse /// An which represents a script object from the agents inventory /// true to set the scripts running state to enabled /// A Unique Transaction ID - /// + /// + /// The following example shows the basic steps necessary to copy a script from the agents inventory into a tasks inventory + /// and assumes the script exists in the agents inventory. /// - /// uint Prim = 95899503; // Fake prim ID - /// UUID Script = UUID.Parse("92a7fe8a-e949-dd39-a8d8-1681d8673232"); // Fake Script UUID in Inventory + /// uint primID = 95899503; // Fake prim ID + /// UUID scriptID = UUID.Parse("92a7fe8a-e949-dd39-a8d8-1681d8673232"); // Fake Script UUID in Inventory /// /// Client.Inventory.FolderContents(Client.Inventory.FindFolderForType(AssetType.LSLText), Client.Self.AgentID, /// false, true, InventorySortOrder.ByName, 10000); /// - /// UUID Transaction = Client.Inventory.RezScript(Prim, (InventoryItem)Client.Inventory.Store[Script]); + /// Client.Inventory.RezScript(primID, (InventoryItem)Client.Inventory.Store[scriptID]); /// - /// + /// + // DocTODO: what does the return UUID correlate to if anything? public UUID CopyScriptToTask(uint objectLocalID, InventoryItem item, bool enableScript) { UUID transactionID = UUID.Random(); RezScriptPacket ScriptPacket = new RezScriptPacket(); - ScriptPacket.AgentData.AgentID = _Client.Self.AgentID; - ScriptPacket.AgentData.SessionID = _Client.Self.SessionID; + ScriptPacket.AgentData.AgentID = Client.Self.AgentID; + ScriptPacket.AgentData.SessionID = Client.Self.SessionID; ScriptPacket.UpdateBlock.ObjectLocalID = objectLocalID; ScriptPacket.UpdateBlock.Enabled = enableScript; @@ -2728,43 +2847,47 @@ namespace OpenMetaverse ScriptPacket.InventoryBlock.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); ScriptPacket.InventoryBlock.CRC = ItemCRC(item); - _Client.Network.SendPacket(ScriptPacket); + Client.Network.SendPacket(ScriptPacket); return transactionID; } /// - /// Send a request to the simulator to get the running status of a script. The reply will come back via the EventQueue - /// in a ScriptRunningReply message + /// Request the running status of a script contained in a task (primitive) inventory /// - /// The object containing the script - /// The script contained in the task inventorys - public void GetScriptRunning(UUID objectID, UUID scriptID) + /// The ID of the primitive containing the script + /// The ID of the script + /// The event can be used to obtain the results of the + /// request + /// + public void RequestGetScriptRunning(UUID objectID, UUID scriptID) { GetScriptRunningPacket request = new GetScriptRunningPacket(); request.Script.ObjectID = objectID; request.Script.ItemID = scriptID; - _Client.Network.SendPacket(request); + + Client.Network.SendPacket(request); } /// - /// Sets a script running state which is in a task inventory + /// Send a request to set the running state of a script contained in a task (primitive) inventory /// - /// The object containing the script - /// The script contained in the task inventorys + /// The ID of the primitive containing the script + /// The ID of the script /// true to set the script running, false to stop a running script - public void SetScriptRunning(UUID objectID, UUID scriptID, bool running) + /// To verify the change you can use the method combined + /// with the event + public void RequestSetScriptRunning(UUID objectID, UUID scriptID, bool running) { SetScriptRunningPacket request = new SetScriptRunningPacket(); - request.AgentData.AgentID = _Client.Self.AgentID; - request.AgentData.SessionID = _Client.Self.SessionID; - + request.AgentData.AgentID = Client.Self.AgentID; + request.AgentData.SessionID = Client.Self.SessionID; request.Script.Running = running; request.Script.ItemID = scriptID; request.Script.ObjectID = objectID; - _Client.Network.SendPacket(request); + Client.Network.SendPacket(request); } #endregion Task @@ -2781,7 +2904,7 @@ namespace OpenMetaverse _CallbackPos++; if (_ItemCreatedCallbacks.ContainsKey(_CallbackPos)) - Logger.Log("Overwriting an existing ItemCreatedCallback", Helpers.LogLevel.Warning, _Client); + Logger.Log("Overwriting an existing ItemCreatedCallback", Helpers.LogLevel.Warning, Client); _ItemCreatedCallbacks[_CallbackPos] = callback; @@ -2799,7 +2922,7 @@ namespace OpenMetaverse _CallbackPos++; if (_ItemCopiedCallbacks.ContainsKey(_CallbackPos)) - Logger.Log("Overwriting an existing ItemsCopiedCallback", Helpers.LogLevel.Warning, _Client); + Logger.Log("Overwriting an existing ItemsCopiedCallback", Helpers.LogLevel.Warning, Client); _ItemCopiedCallbacks[_CallbackPos] = callback; @@ -3111,7 +3234,7 @@ namespace OpenMetaverse } else if (key == "creator_id") { - + UUID.TryParse(value, out creatorID); } else if (key == "owner_id") @@ -3238,17 +3361,17 @@ namespace OpenMetaverse return items; } - + #endregion Helper Functions - #region Callbacks + #region Internal Callbacks void Self_IM(object sender, InstantMessageEventArgs e) { // TODO: MainAvatar.InstantMessageDialog.GroupNotice can also be an inventory offer, should we // handle it here? - if (OnObjectOffered != null && + if (m_InventoryObjectOffered != null && (e.IM.Dialog == InstantMessageDialog.InventoryOffered || e.IM.Dialog == InstantMessageDialog.TaskInventoryOffered)) { @@ -3266,7 +3389,7 @@ namespace OpenMetaverse } else { - Logger.Log("Malformed inventory offer from agent", Helpers.LogLevel.Warning, _Client); + Logger.Log("Malformed inventory offer from agent", Helpers.LogLevel.Warning, Client); return; } } @@ -3279,7 +3402,7 @@ namespace OpenMetaverse } else { - Logger.Log("Malformed inventory offer from object", Helpers.LogLevel.Warning, _Client); + Logger.Log("Malformed inventory offer from object", Helpers.LogLevel.Warning, Client); return; } } @@ -3291,20 +3414,24 @@ namespace OpenMetaverse try { ImprovedInstantMessagePacket imp = new ImprovedInstantMessagePacket(); - imp.AgentData.AgentID = _Client.Self.AgentID; - imp.AgentData.SessionID = _Client.Self.SessionID; + imp.AgentData.AgentID = Client.Self.AgentID; + imp.AgentData.SessionID = Client.Self.SessionID; imp.MessageBlock.FromGroup = false; imp.MessageBlock.ToAgentID = e.IM.FromAgentID; imp.MessageBlock.Offline = 0; imp.MessageBlock.ID = e.IM.IMSessionID; imp.MessageBlock.Timestamp = 0; - imp.MessageBlock.FromAgentName = Utils.StringToBytes(_Client.Self.Name); + imp.MessageBlock.FromAgentName = Utils.StringToBytes(Client.Self.Name); imp.MessageBlock.Message = Utils.EmptyBytes; imp.MessageBlock.ParentEstateID = 0; imp.MessageBlock.RegionID = UUID.Zero; - imp.MessageBlock.Position = _Client.Self.SimPosition; + imp.MessageBlock.Position = Client.Self.SimPosition; - if (OnObjectOffered(e.IM, type, objectID, fromTask)) + InventoryObjectOfferedEventArgs args = new InventoryObjectOfferedEventArgs(e.IM, type, objectID, fromTask); + + OnInventoryObjectOffered(args); + + if (args.Accept) { // Accept the inventory offer switch (e.IM.Dialog) @@ -3341,11 +3468,11 @@ namespace OpenMetaverse imp.MessageBlock.BinaryBucket = Utils.EmptyBytes; } - _Client.Network.SendPacket(imp, e.Simulator); + Client.Network.SendPacket(imp, e.Simulator); } catch (Exception ex) { - Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); + Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } } @@ -3357,11 +3484,11 @@ namespace OpenMetaverse byte[] itemData = (byte[])args[1]; int millisecondsTimeout = (int)args[2]; OSDMap request = (OSDMap)args[3]; - + if (result == null) { try { callback(false, error.Message, UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } return; } @@ -3384,42 +3511,194 @@ namespace OpenMetaverse } else if (status == "complete") { - Logger.DebugLog("CreateItemFromAsset: completed"); + Logger.DebugLog("CreateItemFromAsset: completed"); if (contents.ContainsKey("new_inventory_item") && contents.ContainsKey("new_asset")) { // Request full update on the item in order to update the local store - RequestFetchInventory(contents["new_inventory_item"].AsUUID(), _Client.Self.AgentID); + RequestFetchInventory(contents["new_inventory_item"].AsUUID(), Client.Self.AgentID); try { callback(true, String.Empty, contents["new_inventory_item"].AsUUID(), contents["new_asset"].AsUUID()); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } else { try { callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } else { // Failure try { callback(false, status, UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } - private void SaveAssetIntoInventoryHandler(object sender, PacketReceivedEventArgs e) + + private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason, LoginResponseData replyData) { - if (OnSaveAssetToInventory != null) + if (loginSuccess) + { + // Initialize the store here so we know who owns it: + _Store = new Inventory(Client, this, Client.Self.AgentID); + Logger.DebugLog("Setting InventoryRoot to " + replyData.InventoryRoot.ToString(), Client); + InventoryFolder rootFolder = new InventoryFolder(replyData.InventoryRoot); + rootFolder.Name = String.Empty; + rootFolder.ParentUUID = UUID.Zero; + _Store.RootFolder = rootFolder; + + for (int i = 0; i < replyData.InventorySkeleton.Length; i++) + _Store.UpdateNodeFor(replyData.InventorySkeleton[i]); + + InventoryFolder libraryRootFolder = new InventoryFolder(replyData.LibraryRoot); + libraryRootFolder.Name = String.Empty; + libraryRootFolder.ParentUUID = UUID.Zero; + _Store.LibraryFolder = libraryRootFolder; + + for (int i = 0; i < replyData.LibrarySkeleton.Length; i++) + _Store.UpdateNodeFor(replyData.LibrarySkeleton[i]); + } + } + + private void UploadInventoryAssetResponse(CapsClient client, OSD result, Exception error) + { + OSDMap contents = result as OSDMap; + KeyValuePair kvp = (KeyValuePair)(((object[])client.UserData)[0]); + InventoryUploadedAssetCallback callback = kvp.Key; + byte[] itemData = (byte[])kvp.Value; + + if (error == null && contents != null) + { + string status = contents["state"].AsString(); + + if (status == "upload") + { + Uri uploadURL = contents["uploader"].AsUri(); + + if (uploadURL != null) + { + // This makes the assumption that all uploads go to CurrentSim, to avoid + // the problem of HttpRequestState not knowing anything about simulators + CapsClient upload = new CapsClient(uploadURL); + upload.OnComplete += UploadInventoryAssetResponse; + upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; + upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); + } + else + { + try { callback(false, "Missing uploader URL", UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else if (status == "complete") + { + if (contents.ContainsKey("new_asset")) + { + // Request full item update so we keep store in sync + RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); + + try { callback(true, String.Empty, (UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + else + { + try { callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else + { + try { callback(false, status, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else + { + string message = "Unrecognized or empty response"; + + if (error != null) + { + if (error is WebException) + message = ((HttpWebResponse)((WebException)error).Response).StatusDescription; + + if (message == null || message == "None") + message = error.Message; + } + + try { callback(false, message, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + + private void UpdateScriptAgentInventoryResponse(CapsClient client, OSD result, Exception error) + { + KeyValuePair kvp = (KeyValuePair)(((object[])client.UserData)[0]); + ScriptUpdatedCallback callback = kvp.Key; + byte[] itemData = (byte[])kvp.Value; + + if (result == null) + { + try { callback(false, error.Message, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + return; + } + + OSDMap contents = (OSDMap)result; + + string status = contents["state"].AsString(); + if (status == "upload") + { + string uploadURL = contents["uploader"].AsString(); + + CapsClient upload = new CapsClient(new Uri(uploadURL)); + upload.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse); + upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; + upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT); + } + else if (status == "complete" && callback != null) + { + if (contents.ContainsKey("new_asset")) + { + // Request full item update so we keep store in sync + RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); + + try { callback(true, status, (UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + else + { + try { callback(false, "Failed to parse asset UUID", UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + else if (callback != null) + { + try { callback(false, status, UUID.Zero, UUID.Zero); } + catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } + } + } + #endregion Internal Handlers + + #region Packet Handlers + + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void SaveAssetIntoInventoryHandler(object sender, PacketReceivedEventArgs e) + { + if (m_SaveAssetToInventory != null) { Packet packet = e.Packet; - + SaveAssetIntoInventoryPacket save = (SaveAssetIntoInventoryPacket)packet; - try { OnSaveAssetToInventory(save.InventoryData.ItemID, save.InventoryData.NewAssetID); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + OnSaveAssetToInventory(new SaveAssetToInventoryEventArgs(save.InventoryData.ItemID, save.InventoryData.NewAssetID)); } } + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data protected void InventoryDescendentsHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; @@ -3467,7 +3746,7 @@ namespace OpenMetaverse * 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 + if ((AssetType)reply.ItemData[i].Type == AssetType.Object && (InventoryType)reply.ItemData[i].InvType == InventoryType.Texture) { item = CreateInventoryItem(InventoryType.Attachment, reply.ItemData[i].ItemID); @@ -3478,7 +3757,7 @@ namespace OpenMetaverse 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; @@ -3515,7 +3794,7 @@ namespace OpenMetaverse else { Logger.Log("Don't have a reference to FolderID " + reply.AgentData.FolderID.ToString() + - " or it is not a folder", Helpers.LogLevel.Error, _Client); + " or it is not a folder", Helpers.LogLevel.Error, Client); return; } @@ -3523,7 +3802,7 @@ namespace OpenMetaverse { Logger.Log("Got an outdated InventoryDescendents packet for folder " + parentFolder.Name + ", this version = " + reply.AgentData.Version + ", latest version = " + parentFolder.Version, - Helpers.LogLevel.Warning, _Client); + Helpers.LogLevel.Warning, Client); return; } @@ -3555,13 +3834,13 @@ namespace OpenMetaverse { if (search.Level == search.Path.Length - 1) { - Logger.DebugLog("Finished path search of " + String.Join("/", search.Path), _Client); + 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) + if (m_FindObjectByPathReply != null) { - try { OnFindObjectByPath(String.Join("/", search.Path), folderContents[j].UUID); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + OnFindObjectByPathReply(new FindObjectByPathReplyEventArgs(String.Join("/", search.Path), + folderContents[j].UUID)); } // Remove this entry and restart the loop since we are changing the collection size @@ -3572,13 +3851,13 @@ namespace OpenMetaverse { // 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.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, + RequestFolderContents(search.Folder, search.Owner, true, true, InventorySortOrder.ByName); } } @@ -3590,10 +3869,9 @@ namespace OpenMetaverse #endregion FindObjectsByPath Handling // Callback for inventory folder contents being updated - if (OnFolderUpdated != null) + if (m_FolderUpdated != null) { - try { OnFolderUpdated(parentFolder.UUID); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + OnFolderUpdated(new FolderUpdatedEventArgs(parentFolder.UUID)); } } @@ -3603,10 +3881,12 @@ namespace OpenMetaverse /// taken into inventory, when an item is created using the CreateInventoryItem /// packet, or when an object is purchased /// + /// The sender + /// The EventArgs object containing the packet data protected void UpdateCreateInventoryItemHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; - + UpdateCreateInventoryItemPacket reply = packet as UpdateCreateInventoryItemPacket; foreach (UpdateCreateInventoryItemPacket.InventoryDataBlock dataBlock in reply.InventoryData) @@ -3614,11 +3894,11 @@ namespace OpenMetaverse if (dataBlock.InvType == (sbyte)InventoryType.Folder) { Logger.Log("Received InventoryFolder in an UpdateCreateInventoryItem packet, this should not happen!", - Helpers.LogLevel.Error, _Client); + Helpers.LogLevel.Error, Client); continue; } - InventoryItem item = CreateInventoryItem((InventoryType)dataBlock.InvType,dataBlock.ItemID); + InventoryItem item = CreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID); item.AssetType = (AssetType)dataBlock.Type; item.AssetUUID = dataBlock.AssetID; item.CreationDate = Utils.UnixTimeToDateTime(dataBlock.CreationDate); @@ -3667,7 +3947,7 @@ namespace OpenMetaverse _ItemCreatedCallbacks.Remove(dataBlock.CallbackID); try { createdCallback(true, item); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } // TODO: Is this callback even triggered when items are copied? @@ -3678,23 +3958,25 @@ namespace OpenMetaverse _ItemCopiedCallbacks.Remove(dataBlock.CallbackID); try { copyCallback(item); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } - + //This is triggered when an item is received from a task - if (OnTaskItemReceived != null) + if (m_TaskItemReceived != null) { - try { OnTaskItemReceived(item.UUID, dataBlock.FolderID, item.CreatorID, item.AssetUUID, - item.InventoryType); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + OnTaskItemReceived(new TaskItemReceivedEventArgs(item.UUID, dataBlock.FolderID, + item.CreatorID, item.AssetUUID, item.InventoryType)); } } } + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data protected void MoveInventoryItemHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; - + MoveInventoryItemPacket move = (MoveInventoryItemPacket)packet; for (int i = 0; i < move.InventoryData.Length; i++) @@ -3705,14 +3987,17 @@ namespace OpenMetaverse Logger.Log(String.Format( "MoveInventoryItemHandler: Item {0} is moving to Folder {1} with new name \"{2}\". Someone write this function!", move.InventoryData[i].ItemID.ToString(), move.InventoryData[i].FolderID.ToString(), - newName), Helpers.LogLevel.Warning, _Client); + newName), Helpers.LogLevel.Warning, Client); } } - private void BulkUpdateInventoryHandler(object sender, PacketReceivedEventArgs e) + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void BulkUpdateInventoryHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; - + BulkUpdateInventoryPacket update = packet as BulkUpdateInventoryPacket; if (update.FolderData.Length > 0 && update.FolderData[0].FolderID != UUID.Zero) @@ -3720,7 +4005,7 @@ namespace OpenMetaverse foreach (BulkUpdateInventoryPacket.FolderDataBlock dataBlock in update.FolderData) { if (!_Store.Contains(dataBlock.FolderID)) - Logger.Log("Received BulkUpdate for unknown folder: " + dataBlock.FolderID, Helpers.LogLevel.Warning, _Client); + Logger.Log("Received BulkUpdate for unknown folder: " + dataBlock.FolderID, Helpers.LogLevel.Warning, Client); InventoryFolder folder = new InventoryFolder(dataBlock.FolderID); folder.Name = Utils.BytesToString(dataBlock.Name); @@ -3739,7 +4024,7 @@ namespace OpenMetaverse // If we are given a folder of items, the item information might arrive before the folder // (parent) is in the store if (!_Store.Contains(dataBlock.ItemID)) - Logger.Log("Received BulkUpdate for unknown item: " + dataBlock.ItemID, Helpers.LogLevel.Warning, _Client); + Logger.Log("Received BulkUpdate for unknown item: " + dataBlock.ItemID, Helpers.LogLevel.Warning, Client); InventoryItem item = SafeCreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID); @@ -3772,7 +4057,7 @@ namespace OpenMetaverse _ItemCreatedCallbacks.Remove(dataBlock.CallbackID); try { callback(true, item); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } // Look for an "item copied" callback @@ -3782,24 +4067,27 @@ namespace OpenMetaverse _ItemCopiedCallbacks.Remove(dataBlock.CallbackID); try { copyCallback(item); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); } } } } } - private void FetchInventoryReplyHandler(object sender, PacketReceivedEventArgs e) + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void FetchInventoryReplyHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; - + FetchInventoryReplyPacket reply = packet as FetchInventoryReplyPacket; - foreach (FetchInventoryReplyPacket.InventoryDataBlock dataBlock in reply.InventoryData) + foreach (FetchInventoryReplyPacket.InventoryDataBlock dataBlock in reply.InventoryData) { if (dataBlock.InvType == (sbyte)InventoryType.Folder) { Logger.Log("Received FetchInventoryReply for an inventory folder, this should not happen!", - Helpers.LogLevel.Error, _Client); + Helpers.LogLevel.Error, Client); continue; } @@ -3817,10 +4105,10 @@ namespace OpenMetaverse item.OwnerID = dataBlock.OwnerID; item.ParentUUID = dataBlock.FolderID; item.Permissions = new Permissions( - dataBlock.BaseMask, - dataBlock.EveryoneMask, - dataBlock.GroupMask, - dataBlock.NextOwnerMask, + dataBlock.BaseMask, + dataBlock.EveryoneMask, + dataBlock.GroupMask, + dataBlock.NextOwnerMask, dataBlock.OwnerMask); item.SalePrice = dataBlock.SalePrice; item.SaleType = (SaleType)dataBlock.SaleType; @@ -3829,191 +4117,186 @@ namespace OpenMetaverse _Store[item.UUID] = item; // Fire the callback for an item being fetched - if (OnItemReceived != null) + if (m_ItemReceived != null) { - try { OnItemReceived(item); } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + OnItemReceived(new ItemReceivedEventArgs(item)); } } } - private void ReplyTaskInventoryHandler(object sender, PacketReceivedEventArgs e) + /// Process an incoming packet and raise the appropriate events + /// The sender + /// The EventArgs object containing the packet data + protected void ReplyTaskInventoryHandler(object sender, PacketReceivedEventArgs e) { - if (OnTaskInventoryReply != null) + if (m_TaskInventoryReply != null) { Packet packet = e.Packet; - + ReplyTaskInventoryPacket reply = (ReplyTaskInventoryPacket)packet; - try - { - OnTaskInventoryReply(reply.InventoryData.TaskID, reply.InventoryData.Serial, - Utils.BytesToString(reply.InventoryData.Filename)); - } - catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, _Client, ex); } + OnTaskInventoryReply(new TaskInventoryReplyEventArgs(reply.InventoryData.TaskID, reply.InventoryData.Serial, + Utils.BytesToString(reply.InventoryData.Filename))); } } - - - private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason, LoginResponseData replyData) + + protected void ScriptRunningReplyMessageHandler(string capsKey, Interfaces.IMessage message, Simulator simulator) { - if (loginSuccess) + if (m_ScriptRunningReply != null) { - // Initialize the store here so we know who owns it: - _Store = new Inventory(_Client, this, _Client.Self.AgentID); - Logger.DebugLog("Setting InventoryRoot to " + replyData.InventoryRoot.ToString(), _Client); - InventoryFolder rootFolder = new InventoryFolder(replyData.InventoryRoot); - rootFolder.Name = String.Empty; - rootFolder.ParentUUID = UUID.Zero; - _Store.RootFolder = rootFolder; - - for (int i = 0; i < replyData.InventorySkeleton.Length; i++) - _Store.UpdateNodeFor(replyData.InventorySkeleton[i]); - - InventoryFolder libraryRootFolder = new InventoryFolder(replyData.LibraryRoot); - libraryRootFolder.Name = String.Empty; - libraryRootFolder.ParentUUID = UUID.Zero; - _Store.LibraryFolder = libraryRootFolder; - - for(int i = 0; i < replyData.LibrarySkeleton.Length; i++) - _Store.UpdateNodeFor(replyData.LibrarySkeleton[i]); + ScriptRunningReplyMessage msg = (ScriptRunningReplyMessage)message; + OnScriptRunningReply(new ScriptRunningReplyEventArgs(msg.ObjectID, msg.ItemID, msg.Mono, msg.Running)); } } - private void UploadInventoryAssetResponse(CapsClient client, OSD result, Exception error) - { - OSDMap contents = result as OSDMap; - KeyValuePair kvp = (KeyValuePair)(((object[])client.UserData)[0]); - InventoryUploadedAssetCallback callback = kvp.Key; - byte[] itemData = (byte[])kvp.Value; - - if (error == null && contents != null) - { - string status = contents["state"].AsString(); - - if (status == "upload") - { - Uri uploadURL = contents["uploader"].AsUri(); - - if (uploadURL != null) - { - // This makes the assumption that all uploads go to CurrentSim, to avoid - // the problem of HttpRequestState not knowing anything about simulators - CapsClient upload = new CapsClient(uploadURL); - upload.OnComplete += UploadInventoryAssetResponse; - upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; - upload.BeginGetResponse(itemData, "application/octet-stream", _Client.Settings.CAPS_TIMEOUT); - } - else - { - try { callback(false, "Missing uploader URL", UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - } - else if (status == "complete") - { - if (contents.ContainsKey("new_asset")) - { - // Request full item update so we keep store in sync - RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); - - try { callback(true, String.Empty, (UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - else - { - try { callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - } - else - { - try { callback(false, status, UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - } - else - { - string message = "Unrecognized or empty response"; - - if (error != null) - { - if (error is WebException) - message = ((HttpWebResponse)((WebException)error).Response).StatusDescription; - - if (message == null || message == "None") - message = error.Message; - } - - try { callback(false, message, UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - } - - /// - /// - /// - /// - /// - /// - private void UpdateScriptAgentInventoryResponse(CapsClient client, OSD result, Exception error) - { - KeyValuePair kvp = (KeyValuePair)(((object[])client.UserData)[0]); - ScriptUpdatedCallback callback = kvp.Key; - byte[] itemData = (byte[])kvp.Value; - - if (result == null) - { - try { callback(false, error.Message, UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - return; - } - - OSDMap contents = (OSDMap)result; - - string status = contents["state"].AsString(); - if (status == "upload") - { - string uploadURL = contents["uploader"].AsString(); - - CapsClient upload = new CapsClient(new Uri(uploadURL)); - upload.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse); - upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) }; - upload.BeginGetResponse(itemData, "application/octet-stream", _Client.Settings.CAPS_TIMEOUT); - } - else if (status == "complete" && callback != null) - { - if (contents.ContainsKey("new_asset")) - { - // Request full item update so we keep store in sync - RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); - - try { callback(true, status, (UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - else - { - try { callback(false, "Failed to parse asset UUID", UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - } - else if (callback != null) - { - try { callback(false, status, UUID.Zero, UUID.Zero); } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - } - - public void ScriptRunningReplyMessageHandler(string capsKey, Interfaces.IMessage message, Simulator simulator) - { - if (OnScriptRunning != null) - { - ScriptRunningReplyMessage msg = (ScriptRunningReplyMessage) message; - try { OnScriptRunning(msg.ObjectID, msg.ItemID, msg.Mono, msg.Running);} - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, _Client, e); } - } - } - - #endregion Callbacks + #endregion Packet Handlers } + + #region EventArgs + + public class InventoryObjectOfferedEventArgs : EventArgs + { + private readonly InstantMessage m_Offer; + private readonly AssetType m_AssetType; + private readonly UUID m_ObjectID; + private readonly bool m_FromTask; + + /// Set to true to accept offer, false to decline it + public bool Accept { get; set; } + public InstantMessage Offer { get { return m_Offer; } } + public AssetType AssetType { get { return m_AssetType; } } + public UUID ObjectID { get { return m_ObjectID; } } + public bool FromTask { get { return m_FromTask; } } + + public InventoryObjectOfferedEventArgs(InstantMessage offerDetails, AssetType type, UUID objectID, bool fromTask) + { + this.Accept = false; + this.m_Offer = offerDetails; + this.m_AssetType = type; + this.m_ObjectID = objectID; + this.m_FromTask = fromTask; + } + } + + public class FolderUpdatedEventArgs : EventArgs + { + private readonly UUID m_FolderID; + public UUID FolderID { get { return m_FolderID; } } + public FolderUpdatedEventArgs(UUID folderID) + { + this.m_FolderID = folderID; + } + } + + public class ItemReceivedEventArgs : EventArgs + { + private readonly InventoryItem m_Item; + + public InventoryItem Item { get { return m_Item; } } + + public ItemReceivedEventArgs(InventoryItem item) + { + this.m_Item = item; + } + } + + public class FindObjectByPathReplyEventArgs : EventArgs + { + private readonly String m_Path; + private readonly UUID m_InventoryObjectID; + + public String Path { get { return m_Path; } } + public UUID InventoryObjectID { get { return m_InventoryObjectID; } } + + public FindObjectByPathReplyEventArgs(string path, UUID inventoryObjectID) + { + this.m_Path = path; + this.m_InventoryObjectID = inventoryObjectID; + } + } + + /// + /// Callback when an inventory object is accepted and received from a + /// task inventory. This is the callback in which you actually get + /// the ItemID, as in ObjectOfferedCallback it is null when received + /// from a task. + /// + public class TaskItemReceivedEventArgs : EventArgs + { + private readonly UUID m_ItemID; + private readonly UUID m_FolderID; + private readonly UUID m_CreatorID; + private readonly UUID m_AssetID; + private readonly InventoryType m_Type; + + public UUID ItemID { get { return m_ItemID; } } + public UUID FolderID { get { return m_FolderID; } } + public UUID CreatorID { get { return m_CreatorID; } } + public UUID AssetID { get { return m_AssetID; } } + public InventoryType Type { get { return m_Type; } } + + public TaskItemReceivedEventArgs(UUID itemID, UUID folderID, UUID creatorID, UUID assetID, InventoryType type) + { + this.m_ItemID = itemID; + this.m_FolderID = folderID; + this.m_CreatorID = creatorID; + this.m_AssetID = assetID; + this.m_Type = type; + } + } + + public class TaskInventoryReplyEventArgs : EventArgs + { + private readonly UUID m_ItemID; + private readonly Int16 m_Serial; + private readonly String m_AssetFilename; + + public UUID ItemID { get { return m_ItemID; } } + public Int16 Serial { get { return m_Serial; } } + public String AssetFilename { get { return m_AssetFilename; } } + + public TaskInventoryReplyEventArgs(UUID itemID, short serial, string assetFilename) + { + this.m_ItemID = itemID; + this.m_Serial = serial; + this.m_AssetFilename = assetFilename; + } + } + + public class SaveAssetToInventoryEventArgs : EventArgs + { + private readonly UUID m_ItemID; + private readonly UUID m_NewAssetID; + + public UUID ItemID { get { return m_ItemID; } } + public UUID NewAssetID { get { return m_NewAssetID; } } + + public SaveAssetToInventoryEventArgs(UUID itemID, UUID newAssetID) + { + this.m_ItemID = itemID; + this.m_NewAssetID = newAssetID; + } + } + + public class ScriptRunningReplyEventArgs : EventArgs + { + private readonly UUID m_ObjectID; + private readonly UUID m_ScriptID; + private readonly bool m_IsMono; + private readonly bool m_IsRunning; + + public UUID ObjectID { get { return m_ObjectID; } } + public UUID ScriptID { get { return m_ScriptID; } } + public bool IsMono { get { return m_IsMono; } } + public bool IsRunning { get { return m_IsRunning; } } + + public ScriptRunningReplyEventArgs(UUID objectID, UUID sctriptID, bool isMono, bool isRunning) + { + this.m_ObjectID = objectID; + this.m_ScriptID = sctriptID; + this.m_IsMono = isMono; + this.m_IsRunning = isRunning; + } + } + #endregion } diff --git a/OpenMetaverse/Login.cs b/OpenMetaverse/Login.cs index 113b5395..9308d67a 100644 --- a/OpenMetaverse/Login.cs +++ b/OpenMetaverse/Login.cs @@ -877,7 +877,7 @@ namespace OpenMetaverse { // FIXME: Now that we're using CAPS we could cancel the current login and start a new one if (CurrentContext != null) - throw new Exception("Login already in progress"); + throw new Exception("Login already in progress"); LoginEvent.Reset(); CurrentContext = loginParams; @@ -1253,13 +1253,8 @@ namespace OpenMetaverse SendPacket(new EconomyDataRequestPacket()); // Update the login message with the MOTD returned from the server - UpdateLoginStatus(LoginStatus.Success, message); - - // Fire an event for connecting to the grid - if (m_LoggedIn != null) - { - OnLoggedIn(new LoggedInEventArgs()); - } + UpdateLoginStatus(LoginStatus.ConnectingToSim, "Authentication Successful"); + } else { @@ -1353,13 +1348,7 @@ namespace OpenMetaverse SendPacket(new EconomyDataRequestPacket()); // Update the login message with the MOTD returned from the server - UpdateLoginStatus(LoginStatus.Success, data.Message); - - // Fire an event for connecting to the grid - if (m_LoggedIn != null) - { - OnLoggedIn(new LoggedInEventArgs()); - } + UpdateLoginStatus(LoginStatus.ConnectingToSim, "Authentication Successful"); } else { diff --git a/OpenMetaverse/NetworkManager.cs b/OpenMetaverse/NetworkManager.cs index 1ec3228f..01e21978 100644 --- a/OpenMetaverse/NetworkManager.cs +++ b/OpenMetaverse/NetworkManager.cs @@ -40,11 +40,25 @@ using OpenMetaverse.Messages.Linden; namespace OpenMetaverse { /// - /// This exception is thrown whenever a network operation is attempted - /// without a network connection. + /// This exception is thrown whenever an attempt to send a packet to a simulator where the + /// simulator packet processing is not yet enabled occurs /// - public class NotConnectedException : ApplicationException { } - + public class NotConnectedException : ApplicationException + { + private String m_Message; + public override string Message + { + get + { + return base.Message + " " + m_Message; + } + } + public NotConnectedException(String message) + { + m_Message = message; + } + } + /// /// NetworkManager is responsible for managing the network layer of /// OpenMetaverse. It tracks all the server connections, serializes @@ -119,7 +133,7 @@ namespace OpenMetaverse #endregion Structs #region Delegates - + /// The event subscribers, null of no subscribers private EventHandler m_PacketSent; @@ -143,30 +157,7 @@ namespace OpenMetaverse add { lock (m_PacketSentLock) { m_PacketSent += value; } } remove { lock (m_PacketSentLock) { m_PacketSent -= value; } } } - - /// The event subscribers, null of no subscribers - private EventHandler m_LoggedIn; - ///Raises the LoggedIn Event - /// A LoggedInEventArgs object containing - /// the data sent from the simulator - protected virtual void OnLoggedIn(LoggedInEventArgs e) - { - EventHandler handler = m_LoggedIn; - if (handler != null) - handler(this, e); - } - - /// Thread sync lock object - private readonly object m_LoggedInLock = new object(); - - /// Raised when the login server confirms we are logged in - public event EventHandler LoggedIn - { - add { lock (m_LoggedInLock) { m_LoggedIn += value; } } - remove { lock (m_LoggedInLock) { m_LoggedIn -= value; } } - } - /// The event subscribers, null of no subscribers private EventHandler m_LoggedOut; @@ -190,7 +181,7 @@ namespace OpenMetaverse add { lock (m_LoggedOutLock) { m_LoggedOut += value; } } remove { lock (m_LoggedOutLock) { m_LoggedOut -= value; } } } - + /// The event subscribers, null of no subscribers private EventHandler m_SimConnecting; @@ -214,7 +205,7 @@ namespace OpenMetaverse add { lock (m_SimConnectingLock) { m_SimConnecting += value; } } remove { lock (m_SimConnectingLock) { m_SimConnecting -= value; } } } - + /// The event subscribers, null of no subscribers private EventHandler m_SimConnected; @@ -238,7 +229,7 @@ namespace OpenMetaverse add { lock (m_SimConnectedLock) { m_SimConnected += value; } } remove { lock (m_SimConnectedLock) { m_SimConnected -= value; } } } - + /// The event subscribers, null of no subscribers private EventHandler m_SimDisconnected; @@ -262,7 +253,7 @@ namespace OpenMetaverse add { lock (m_SimDisconnectedLock) { m_SimDisconnected += value; } } remove { lock (m_SimDisconnectedLock) { m_SimDisconnected -= value; } } } - + /// The event subscribers, null of no subscribers private EventHandler m_Disconnected; @@ -286,7 +277,7 @@ namespace OpenMetaverse add { lock (m_DisconnectedLock) { m_Disconnected += value; } } remove { lock (m_DisconnectedLock) { m_Disconnected -= value; } } } - + /// The event subscribers, null of no subscribers private EventHandler m_SimChanged; @@ -310,7 +301,7 @@ namespace OpenMetaverse add { lock (m_SimChangedLock) { m_SimChanged += value; } } remove { lock (m_SimChangedLock) { m_SimChanged -= value; } } } - + /// The event subscribers, null of no subscribers private EventHandler m_EventQueueRunning; @@ -380,7 +371,7 @@ namespace OpenMetaverse private uint _CircuitCode; private Simulator _CurrentSim = null; private bool connected = false; - + /// /// Default constructor /// @@ -388,7 +379,7 @@ namespace OpenMetaverse public NetworkManager(GridClient client) { Client = client; - + PacketEvents = new PacketEventDictionary(client); CapsEvents = new CapsEventDictionary(client); @@ -397,12 +388,12 @@ namespace OpenMetaverse // Register the internal callbacks RegisterCallback(PacketType.RegionHandshake, RegionHandshakeHandler); - RegisterCallback(PacketType.StartPingCheck, StartPingCheckHandler); + RegisterCallback(PacketType.StartPingCheck, StartPingCheckHandler); RegisterCallback(PacketType.DisableSimulator, DisableSimulatorHandler); RegisterCallback(PacketType.KickUser, KickUserHandler); RegisterCallback(PacketType.LogoutReply, LogoutReplyHandler); RegisterCallback(PacketType.CompletePingCheck, CompletePingCheckHandler); - RegisterCallback(PacketType.SimStats, SimStatsHandler); + RegisterCallback(PacketType.SimStats, SimStatsHandler); // GLOBAL SETTING: Don't force Expect-100: Continue headers on HTTP POST calls ServicePointManager.Expect100Continue = false; @@ -464,8 +455,25 @@ namespace OpenMetaverse /// Packet to send public void SendPacket(Packet packet) { - if (CurrentSim != null && CurrentSim.Connected) - CurrentSim.SendPacket(packet); + // try CurrentSim, however directly after login this will + // be null, so if it is, we'll try to find the first simulator + // we're connected to in order to send the packet. + Simulator simulator = CurrentSim; + + if (simulator == null && Client.Network.Simulators.Count >= 1) + { + Logger.DebugLog("CurrentSim object was null, using first found connected simulator", Client); + simulator = Client.Network.Simulators[0]; + } + + if (simulator != null && simulator.Connected) + { + simulator.SendPacket(packet); + } + else + { + throw new NotConnectedException("Packet received before simulator packet processing threads running, make certain you are completely logged in"); + } } /// @@ -476,7 +484,13 @@ namespace OpenMetaverse public void SendPacket(Packet packet, Simulator simulator) { if (simulator != null) + { simulator.SendPacket(packet); + } + else + { + throw new NotConnectedException("Packet received before simulator packet processing threads running, make certain you are completely logged in"); + } } /// @@ -527,6 +541,7 @@ namespace OpenMetaverse if (!connected) { // Mark that we are connecting/connected to the grid + // connected = true; // Open the queues in case this is a reconnect and they were shut down @@ -535,29 +550,31 @@ namespace OpenMetaverse // Start the packet decoding thread Thread decodeThread = new Thread(new ThreadStart(IncomingPacketHandler)); + decodeThread.Name = "Incoming UDP packet dispatcher"; decodeThread.Start(); // Start the packet sending thread Thread sendThread = new Thread(new ThreadStart(OutgoingPacketHandler)); - sendThread.Start(); + sendThread.Name = "Outgoing UDP packet dispatcher"; + sendThread.Start(); } - // Fire the OnSimConnecting event + // raise the SimConnecting event and allow any event + // subscribers to cancel the connection if (m_SimConnecting != null) { - try - { - SimConnectingEventArgs args = new SimConnectingEventArgs(simulator); - OnSimConnecting(args); + SimConnectingEventArgs args = new SimConnectingEventArgs(simulator); + OnSimConnecting(args); - if (args.Cancel) + if (args.Cancel) + { + // Callback is requesting that we abort this connection + lock (Simulators) { - // Callback is requesting that we abort this connection - lock (Simulators) Simulators.Remove(simulator); - return null; - } + Simulators.Remove(simulator); + } + return null; } - catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } // Attempt to establish a connection to the simulator @@ -570,23 +587,33 @@ namespace OpenMetaverse Client.Settings.SIMULATOR_TIMEOUT, Client.Settings.SIMULATOR_TIMEOUT); } - if (setDefault) SetCurrentSim(simulator, seedcaps); + if (setDefault) + { + SetCurrentSim(simulator, seedcaps); + } // Raise the SimConnected event if (m_SimConnected != null) { OnSimConnected(new SimConnectedEventArgs(simulator)); } - + // If enabled, send an AgentThrottle packet to the server to increase our bandwidth - if (Client.Settings.SEND_AGENT_THROTTLE) Client.Throttle.Set(simulator); + if (Client.Settings.SEND_AGENT_THROTTLE) + { + Client.Throttle.Set(simulator); + } return simulator; } else { // Connection failed, remove this simulator from our list and destroy it - lock (Simulators) Simulators.Remove(simulator); + lock (Simulators) + { + Simulators.Remove(simulator); + } + return null; } } @@ -600,7 +627,9 @@ namespace OpenMetaverse // Send an initial AgentUpdate to complete our movement in to the sim if (Client.Settings.SEND_AGENT_UPDATES) + { Client.Self.Movement.SendUpdate(true, simulator); + } return simulator; } @@ -618,7 +647,7 @@ namespace OpenMetaverse /// has expired and the network layer is manually shut down /// public void Logout() - { + { AutoResetEvent logoutEvent = new AutoResetEvent(false); EventHandler callback = delegate(object sender, LoggedOutEventArgs e) { logoutEvent.Set(); }; @@ -794,16 +823,22 @@ namespace OpenMetaverse { OutgoingPacket outgoingPacket = null; Simulator simulator; - + + if (m_LoginProgress != null) + { + // until this point being authenticated does absolutely no good + OnLoginProgress(new LoginProgressEventArgs(LoginStatus.Success, LoginMessage)); + } + // FIXME: This is kind of ridiculous. Port the HTB code from Simian over ASAP! System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); - + while (connected) { if (PacketOutbox.Dequeue(100, ref outgoingPacket)) { simulator = outgoingPacket.Simulator; - + // Very primitive rate limiting, keeps a fixed buffer of time between each packet stopwatch.Stop(); if (stopwatch.ElapsedMilliseconds < 10) @@ -839,7 +874,7 @@ namespace OpenMetaverse // skip blacklisted packets if (UDPBlacklist.Contains(packet.Type.ToString())) { - Logger.Log(String.Format("Discarding Blacklisted packet {0} from {1}", + Logger.Log(String.Format("Discarding Blacklisted packet {0} from {1}", packet.Type, simulator.IPEndPoint), Helpers.LogLevel.Warning); return; } @@ -864,7 +899,7 @@ namespace OpenMetaverse Simulator oldSim = CurrentSim; lock (Simulators) CurrentSim = simulator; // CurrentSim is synchronized against Simulators - simulator.SetSeedCaps(seedcaps); + simulator.SetSeedCaps(seedcaps); // If the current simulator changed fire the callback if (m_SimChanged != null && simulator != oldSim) @@ -985,93 +1020,95 @@ namespace OpenMetaverse /// The sender /// The EventArgs object containing the packet data protected void SimStatsHandler(object sender, PacketReceivedEventArgs e) - { - if ( ! Client.Settings.ENABLE_SIMSTATS ) { - return; - } - SimStatsPacket stats = (SimStatsPacket)e.Packet; - for ( int i = 0 ; i < stats.Stat.Length ; i++ ) { - SimStatsPacket.StatBlock s = stats.Stat[i]; - switch (s.StatID ) - { - case 0: + { + if (!Client.Settings.ENABLE_SIMSTATS) + { + return; + } + SimStatsPacket stats = (SimStatsPacket)e.Packet; + for (int i = 0; i < stats.Stat.Length; i++) + { + SimStatsPacket.StatBlock s = stats.Stat[i]; + switch (s.StatID) + { + case 0: e.Simulator.Stats.Dilation = s.StatValue; - break; - case 1: + break; + case 1: e.Simulator.Stats.FPS = Convert.ToInt32(s.StatValue); - break; - case 2: + break; + case 2: e.Simulator.Stats.PhysicsFPS = s.StatValue; - break; - case 3: + break; + case 3: e.Simulator.Stats.AgentUpdates = s.StatValue; - break; - case 4: + break; + case 4: e.Simulator.Stats.FrameTime = s.StatValue; - break; - case 5: + break; + case 5: e.Simulator.Stats.NetTime = s.StatValue; - break; + break; case 6: e.Simulator.Stats.OtherTime = s.StatValue; break; - case 7: + case 7: e.Simulator.Stats.PhysicsTime = s.StatValue; - break; - case 8: + break; + case 8: e.Simulator.Stats.AgentTime = s.StatValue; - break; - case 9: + break; + case 9: e.Simulator.Stats.ImageTime = s.StatValue; - break; - case 10: + break; + case 10: e.Simulator.Stats.ScriptTime = s.StatValue; break; - case 11: + case 11: e.Simulator.Stats.Objects = Convert.ToInt32(s.StatValue); - break; - case 12: + break; + case 12: e.Simulator.Stats.ScriptedObjects = Convert.ToInt32(s.StatValue); - break; - case 13: + break; + case 13: e.Simulator.Stats.Agents = Convert.ToInt32(s.StatValue); - break; - case 14: + break; + case 14: e.Simulator.Stats.ChildAgents = Convert.ToInt32(s.StatValue); - break; - case 15: + break; + case 15: e.Simulator.Stats.ActiveScripts = Convert.ToInt32(s.StatValue); - break; - case 16: + break; + case 16: e.Simulator.Stats.LSLIPS = Convert.ToInt32(s.StatValue); - break; - case 17: + break; + case 17: e.Simulator.Stats.INPPS = Convert.ToInt32(s.StatValue); - break; - case 18: + break; + case 18: e.Simulator.Stats.OUTPPS = Convert.ToInt32(s.StatValue); - break; - case 19: + break; + case 19: e.Simulator.Stats.PendingDownloads = Convert.ToInt32(s.StatValue); - break; - case 20: + break; + case 20: e.Simulator.Stats.PendingUploads = Convert.ToInt32(s.StatValue); - break; - case 21: + break; + case 21: e.Simulator.Stats.VirtualSize = Convert.ToInt32(s.StatValue); - break; - case 22: + break; + case 22: e.Simulator.Stats.ResidentSize = Convert.ToInt32(s.StatValue); - break; - case 23: + break; + case 23: e.Simulator.Stats.PendingLocalUploads = Convert.ToInt32(s.StatValue); - break; - case 24: + break; + case 24: e.Simulator.Stats.UnackedBytes = Convert.ToInt32(s.StatValue); - break; - } - } - } + break; + } + } + } /// Process an incoming packet and raise the appropriate events /// The sender @@ -1111,7 +1148,7 @@ namespace OpenMetaverse simulator.CPUClass = handshake.RegionInfo3.CPUClassID; simulator.CPURatio = handshake.RegionInfo3.CPURatio; simulator.ProductName = Utils.BytesToString(handshake.RegionInfo3.ProductName); - simulator.ProductSku = Utils.BytesToString(handshake.RegionInfo3.ProductSKU); + simulator.ProductSku = Utils.BytesToString(handshake.RegionInfo3.ProductSKU); // Send a RegionHandshakeReply RegionHandshakeReplyPacket reply = new RegionHandshakeReplyPacket(); @@ -1124,7 +1161,7 @@ namespace OpenMetaverse simulator.connected = true; simulator.ConnectedEvent.Set(); } - + protected void EnableSimulatorHandler(string capsKey, IMessage message, Simulator simulator) { if (!Client.Settings.MULTIPLE_SIMS) return; @@ -1177,14 +1214,14 @@ namespace OpenMetaverse #endregion Packet Callbacks } #region EventArgs - + public class PacketReceivedEventArgs : EventArgs { private readonly Packet m_Packet; private readonly Simulator m_Simulator; public Packet Packet { get { return m_Packet; } } - public Simulator Simulator { get { return m_Simulator; } } + public Simulator Simulator { get { return m_Simulator; } } public PacketReceivedEventArgs(Packet packet, Simulator simulator) { @@ -1192,10 +1229,6 @@ namespace OpenMetaverse this.m_Simulator = simulator; } } - - public class LoggedInEventArgs : EventArgs - { - } public class LoggedOutEventArgs : EventArgs { @@ -1216,7 +1249,7 @@ namespace OpenMetaverse public byte[] Data { get { return m_Data; } } public int SentBytes { get { return m_SentBytes; } } - public Simulator Simulator { get { return m_Simulator; } } + public Simulator Simulator { get { return m_Simulator; } } public PacketSentEventArgs(byte[] data, int bytesSent, Simulator simulator) { @@ -1233,8 +1266,9 @@ namespace OpenMetaverse public Simulator Simulator { get { return m_Simulator; } } - public bool Cancel { - get { return m_Cancel; } + public bool Cancel + { + get { return m_Cancel; } set { m_Cancel = value; } } @@ -1261,8 +1295,8 @@ namespace OpenMetaverse private readonly Simulator m_Simulator; private readonly NetworkManager.DisconnectType m_Reason; - public Simulator Simulator { get { return m_Simulator; } } - public NetworkManager.DisconnectType Reason { get { return m_Reason; } } + public Simulator Simulator { get { return m_Simulator; } } + public NetworkManager.DisconnectType Reason { get { return m_Reason; } } public SimDisconnectedEventArgs(Simulator simulator, NetworkManager.DisconnectType reason) { @@ -1276,8 +1310,8 @@ namespace OpenMetaverse private readonly NetworkManager.DisconnectType m_Reason; private readonly String m_Message; - public NetworkManager.DisconnectType Reason { get { return m_Reason; } } - public String Message { get { return m_Message; } } + public NetworkManager.DisconnectType Reason { get { return m_Reason; } } + public String Message { get { return m_Message; } } public DisconnectedEventArgs(NetworkManager.DisconnectType reason, String message) { @@ -1290,7 +1324,7 @@ namespace OpenMetaverse { private readonly Simulator m_PreviousSimulator; - public Simulator PreviousSimulator { get { return m_PreviousSimulator; } } + public Simulator PreviousSimulator { get { return m_PreviousSimulator; } } public SimChangedEventArgs(Simulator previousSimulator) { @@ -1302,7 +1336,7 @@ namespace OpenMetaverse { private readonly Simulator m_Simulator; - public Simulator Simulator { get { return m_Simulator; } } + public Simulator Simulator { get { return m_Simulator; } } public EventQueueRunningEventArgs(Simulator simulator) { diff --git a/OpenMetaverse/TexturePipeline.cs b/OpenMetaverse/TexturePipeline.cs index fc572a38..fdff7b60 100644 --- a/OpenMetaverse/TexturePipeline.cs +++ b/OpenMetaverse/TexturePipeline.cs @@ -164,7 +164,13 @@ namespace OpenMetaverse } // Handle client connected and disconnected events - client.Network.LoggedIn += delegate { Startup(); }; + client.Network.LoginProgress += delegate(object sender, LoginProgressEventArgs e) { + if (e.Status == LoginStatus.Success) + { + Startup(); + } + }; + client.Network.Disconnected += delegate { Shutdown(); }; } diff --git a/Programs/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs b/Programs/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs index 55092cc1..77d5a587 100644 --- a/Programs/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs +++ b/Programs/examples/TestClient/Commands/Inventory/CreateNotecardCommand.cs @@ -139,33 +139,33 @@ namespace OpenMetaverse.TestClient return "Notecard creation failed: " + message; } - InventoryItem FetchItem(UUID itemID) + private InventoryItem FetchItem(UUID itemID) { InventoryItem fetchItem = null; AutoResetEvent fetchItemEvent = new AutoResetEvent(false); - InventoryManager.ItemReceivedCallback itemReceivedCallback = - delegate(InventoryItem item) + EventHandler itemReceivedCallback = + delegate(object sender, ItemReceivedEventArgs e) { - if (item.UUID == itemID) + if (e.Item.UUID == itemID) { - fetchItem = item; + fetchItem = e.Item; fetchItemEvent.Set(); } }; - Client.Inventory.OnItemReceived += itemReceivedCallback; + Client.Inventory.ItemReceived += itemReceivedCallback; Client.Inventory.RequestFetchInventory(itemID, Client.Self.AgentID); fetchItemEvent.WaitOne(INVENTORY_FETCH_TIMEOUT, false); - Client.Inventory.OnItemReceived -= itemReceivedCallback; + Client.Inventory.ItemReceived -= itemReceivedCallback; return fetchItem; } - string DownloadNotecard(UUID itemID, UUID assetID) + private string DownloadNotecard(UUID itemID, UUID assetID) { AutoResetEvent assetDownloadEvent = new AutoResetEvent(false); byte[] notecardData = null; diff --git a/Programs/examples/TestClient/Commands/Inventory/TaskRunningCommand.cs b/Programs/examples/TestClient/Commands/Inventory/TaskRunningCommand.cs index 464605cf..82e7e51c 100644 --- a/Programs/examples/TestClient/Commands/Inventory/TaskRunningCommand.cs +++ b/Programs/examples/TestClient/Commands/Inventory/TaskRunningCommand.cs @@ -67,20 +67,20 @@ namespace OpenMetaverse.TestClient } bool wasRunning = false; - InventoryManager.ScriptRunningCallback callback; + EventHandler callback; using (AutoResetEvent OnScriptRunningReset = new AutoResetEvent(false)) { - callback = ((UUID objectID0, UUID sctriptID, bool isMono, bool isRunning) => + callback = ((object sender, ScriptRunningReplyEventArgs e) => { - if (objectID0 == objectID) + if (e.ObjectID == objectID) { - result += String.Format(" IsMono: {0} IsRunning: {1}", isMono, isRunning); - wasRunning = isRunning; + result += String.Format(" IsMono: {0} IsRunning: {1}", e.IsMono, e.IsRunning); + wasRunning = e.IsRunning; OnScriptRunningReset.Set(); } }); - Client.Inventory.OnScriptRunning += callback; + Client.Inventory.ScriptRunningReply += callback; for (int i = 0; i < items.Count; i++) { @@ -98,7 +98,7 @@ namespace OpenMetaverse.TestClient if (assetType == AssetType.LSLBytecode || assetType == AssetType.LSLText) { OnScriptRunningReset.Reset(); - Client.Inventory.GetScriptRunning(objectID, item.UUID); + Client.Inventory.RequestGetScriptRunning(objectID, item.UUID); if (!OnScriptRunningReset.WaitOne(10000, true)) { result += " (no script info)"; @@ -109,7 +109,7 @@ namespace OpenMetaverse.TestClient { OnScriptRunningReset.Reset(); result += " Setting " + setTaskTo + " => "; - Client.Inventory.SetScriptRunning(objectID, item.UUID, setTaskTo); + Client.Inventory.RequestSetScriptRunning(objectID, item.UUID, setTaskTo); if (!OnScriptRunningReset.WaitOne(10000, true)) { result += " (was not set)"; @@ -122,7 +122,7 @@ namespace OpenMetaverse.TestClient } } } - Client.Inventory.OnScriptRunning -= callback; + Client.Inventory.ScriptRunningReply -= callback; return result; } else diff --git a/Programs/examples/TestClient/TestClient.cs b/Programs/examples/TestClient/TestClient.cs index 96325605..7201c76f 100644 --- a/Programs/examples/TestClient/TestClient.cs +++ b/Programs/examples/TestClient/TestClient.cs @@ -54,7 +54,7 @@ namespace OpenMetaverse.TestClient Network.LoginProgress += LoginHandler; Self.IM += Self_IM; Groups.GroupMembersReply += GroupMembersHandler; - Inventory.OnObjectOffered += new InventoryManager.ObjectOfferedCallback(Inventory_OnInventoryObjectReceived); + Inventory.InventoryObjectOffered += Inventory_OnInventoryObjectReceived; Network.RegisterCallback(PacketType.AvatarAppearance, AvatarAppearanceHandler); Network.RegisterCallback(PacketType.AlertMessage, AlertMessageHandler); @@ -189,7 +189,7 @@ namespace OpenMetaverse.TestClient if (p.AgentData.AgentID == e.Simulator.Client.Self.AgentID) { GroupID = p.AgentData.ActiveGroupID; - + GroupMembersRequestID = e.Simulator.Client.Groups.RequestGroupMembers(GroupID); } } @@ -219,20 +219,20 @@ namespace OpenMetaverse.TestClient Logger.Log("[AlertMessage] " + Utils.BytesToString(message.AlertData.Message), Helpers.LogLevel.Info, this); } - private bool Inventory_OnInventoryObjectReceived(InstantMessage offer, AssetType type, - UUID objectID, bool fromTask) + private void Inventory_OnInventoryObjectReceived(object sender, InventoryObjectOfferedEventArgs e) { if (MasterKey != UUID.Zero) { - if (offer.FromAgentID != MasterKey) - return false; + if (e.Offer.FromAgentID != MasterKey) + return; } - else if (GroupMembers != null && !GroupMembers.ContainsKey(offer.FromAgentID)) + else if (GroupMembers != null && !GroupMembers.ContainsKey(e.Offer.FromAgentID)) { - return false; + return; } - return true; + e.Accept = true; + return; } } }