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; } } }