From b686cebf3dafeb5f704d64b03e37798eccbfd0f8 Mon Sep 17 00:00:00 2001 From: Michael Cortez Date: Tue, 19 Dec 2006 23:13:04 +0000 Subject: [PATCH] Begining major rework of Asset/Inventory code. Doing a lot of refectoing. What's in here so far? + Inventory, Asset and Image managers are now directly apart of the SecondLife class + Root Inventory folder has been added to MainAvatar and is set upon login + Inventory is no longer downloaded all at once, you have to request the download of individual folders + Folder downloading is available Asynchronously, and returns a object that has a ManualResetEvent that you can use to optionally block with + The code for AssetManager has been reworked some in prep for allowing Wearables to be Saved/Loaded to/from disk, and for creating new wearables. git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@742 52acb1d6-8a22-11de-b505-999d5b087335 --- .../AssetSystem/AppearanceManager.cs | 207 ++++++------- libsecondlife-cs/AssetSystem/AssetManager.cs | 37 +-- .../InventorySystem/InventoryFolder.cs | 38 ++- .../InventorySystem/InventoryItem.cs | 6 +- .../InventorySystem/InventoryManager.cs | 199 +++++++------ .../InventorySystem/InventoryPacketHelper.cs | 18 +- libsecondlife-cs/MainAvatar.cs | 3 + libsecondlife-cs/NetworkManager.cs | 7 + libsecondlife-cs/SecondLife.cs | 37 +-- .../examples/IA_ImageTool/ImageTool.cs | 76 ++++- .../examples/IA_InventoryManager/iManager.cs | 271 ++++++++++++++++-- .../IA_MultiImageUpload/MultiImageUpload.cs | 69 ++++- .../examples/IA_NotecardTool/NotecardTool.cs | 72 ++++- .../IA_SimpleInventory/IA_SimpleInventory.cs | 58 ++-- .../IA_TestAsyncImage/IA_TestAsyncImage.cs | 170 ++++++----- .../examples/Teleport/Teleport.cs | 4 +- libsecondlife-cs/libsecondlife.csproj | 2 + 17 files changed, 835 insertions(+), 439 deletions(-) diff --git a/libsecondlife-cs/AssetSystem/AppearanceManager.cs b/libsecondlife-cs/AssetSystem/AppearanceManager.cs index b3e87bef..42c56ac7 100644 --- a/libsecondlife-cs/AssetSystem/AppearanceManager.cs +++ b/libsecondlife-cs/AssetSystem/AppearanceManager.cs @@ -18,30 +18,23 @@ namespace libsecondlife.AssetSystem private uint SerialNum = 1; private ManualResetEvent AgentWearablesSignal = null; - private AgentWearablesUpdatePacket.WearableDataBlock[] AgentWearablesData; + + // This data defines all appearance info for an avatar + public AgentWearablesUpdatePacket.WearableDataBlock[] AgentWearablesData; + public SerializableDictionary AgentAppearanceParams = new SerializableDictionary(); + public TextureEntry AgentTextureEntry = new TextureEntry("C228D1CF4B5D4BA884F4899A0796AA97"); // if this isn't valid, blame JH ;-) + + public AppearanceManager(SecondLife client) { Client = client; - AManager = AssetManager.GetAssetManager(client); + AManager = client.Assets; - Client.Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar); RegisterCallbacks(); } - void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation) - { - if (avatar.ID == Client.Network.AgentID) - { - Console.WriteLine("**********************"); - Console.WriteLine("**********************"); - Console.WriteLine("Saw Myself"); - Console.WriteLine("**********************"); - Console.WriteLine("**********************"); - } - } - private void RegisterCallbacks() { Client.Network.RegisterCallback(libsecondlife.Packets.PacketType.AgentWearablesUpdate, new NetworkManager.PacketCallback(AgentWearablesUpdateCallbackHandler)); @@ -61,33 +54,8 @@ namespace libsecondlife.AssetSystem return AgentWearablesData; } - public void SendAgentSetAppearance() + public void GetAvatarAppearanceInfoFromWearableAssets() { - - TextureEntry textures = new TextureEntry("C228D1CF4B5D4BA884F4899A0796AA97"); // if this isn't valid, blame JH ;-) - - // Face 17 - Under Pants - // textures.CreateFace(17).TextureID = "b0bac26505cc7076202ba2a2e05fd172"; //Default Men's briefs - - // Face 16 - Under Shirt - // textures.CreateFace(16).TextureID = "d283de852dc3dc07dc452e1bfd4cf193"; //Default Men's tank - - // Face 11 - Eyes - // textures.CreateFace(11).TextureID = "3abd329a78478984ac1cb95f4ef35fbe"; //Default Eye - - // Face 10 - - // textures.CreateFace(10).TextureID = "c24403bc4569361852b31917ad733035"; //Default - - // Face 9 - - // textures.CreateFace(9).TextureID = "a88225377555cf975720aa128e47f934"; //Default - - // Face 8 - - // textures.CreateFace(8).TextureID = "472ccc472a4e2556d082f7bb708bcca7"; //Default - - - - Dictionary AgentAppearance = new Dictionary(); - foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in GetWearables()) { if (wdb.ItemID == LLUUID.Zero) @@ -124,13 +92,12 @@ namespace libsecondlife.AssetSystem foreach (KeyValuePair texture in bp.textures) { - Console.WriteLine(texture.Key + " : " + texture.Value); - textures.CreateFace(texture.Key).TextureID = texture.Value; + AgentTextureEntry.CreateFace(texture.Key).TextureID = texture.Value; } foreach (KeyValuePair kvp in bp.parameters) { - AgentAppearance[kvp.Key] = bp.parameters[kvp.Key]; + AgentAppearanceParams[kvp.Key] = bp.parameters[kvp.Key]; } } catch (Exception e) @@ -145,46 +112,9 @@ namespace libsecondlife.AssetSystem } } - - Dictionary VisualParams = new Dictionary(); - - float maxVal = 0; - float minVal = 0; - uint packetIdx = 0; - float range = 0; - float percentage = 0; - byte packetVal = 0; - - foreach (KeyValuePair kvp in AgentAppearance) - { - packetIdx = AppearanceManager.GetAgentSetAppearanceIndex(kvp.Key) - 1; //TODO/FIXME: this should be zero indexed, not 1 based. - maxVal = BodyShapeParams.GetValueMax(kvp.Key); - minVal = BodyShapeParams.GetValueMin(kvp.Key); - - range = maxVal - minVal; - - percentage = (kvp.Value - minVal) / range; - - packetVal = (byte)(percentage * (byte)255); - - VisualParams[packetIdx] = packetVal; - } - - - AgentSetAppearancePacket p = new AgentSetAppearancePacket(); - p.AgentData.AgentID = Client.Network.AgentID; - p.AgentData.SessionID = Client.Network.SessionID; - p.AgentData.SerialNum = ++SerialNum; - - float AV_Height_Range = 2.025506f - 1.50856f; - float AV_Height = 1.50856f + (((float)VisualParams[25] / 255.0f) * AV_Height_Range); - - p.AgentData.Size = new LLVector3(0.45f, 0.6f, AV_Height); -// p.AgentData.Size = new LLVector3(0.45f, 0.6f, 1.35187f); - // p.ObjectData.TextureEntry = textures.ToBytes(); - - foreach( uint faceid in textures.FaceTextures.Keys ) + // Correct the order of the textures + foreach (uint faceid in AgentTextureEntry.FaceTextures.Keys) { switch (faceid) { @@ -210,22 +140,78 @@ namespace libsecondlife.AssetSystem } //Re-order texture faces to match Linden Labs internal data structure. - TextureEntry te2 = new TextureEntry(textures.DefaultTexture.TextureID); - te2.CreateFace(18).TextureID = textures.GetFace(18).TextureID; - te2.CreateFace(17).TextureID = textures.GetFace(17).TextureID; - te2.CreateFace(16).TextureID = textures.GetFace(16).TextureID; - te2.CreateFace(15).TextureID = textures.GetFace(15).TextureID; - te2.CreateFace(2).TextureID = textures.GetFace(2).TextureID; - te2.CreateFace(12).TextureID = textures.GetFace(12).TextureID; - te2.CreateFace(7).TextureID = textures.GetFace(7).TextureID; - te2.CreateFace(6).TextureID = textures.GetFace(6).TextureID; - te2.CreateFace(5).TextureID = textures.GetFace(5).TextureID; - te2.CreateFace(4).TextureID = textures.GetFace(4).TextureID; - te2.CreateFace(3).TextureID = textures.GetFace(3).TextureID; - te2.CreateFace(1).TextureID = textures.GetFace(1).TextureID; - te2.CreateFace(0).TextureID = textures.GetFace(0).TextureID; - p.ObjectData.TextureEntry = te2.ToBytes(); + TextureEntry te2 = new TextureEntry(AgentTextureEntry.DefaultTexture.TextureID); + te2.CreateFace(18).TextureID = AgentTextureEntry.GetFace(18).TextureID; + te2.CreateFace(17).TextureID = AgentTextureEntry.GetFace(17).TextureID; + te2.CreateFace(16).TextureID = AgentTextureEntry.GetFace(16).TextureID; + te2.CreateFace(15).TextureID = AgentTextureEntry.GetFace(15).TextureID; + te2.CreateFace(2).TextureID = AgentTextureEntry.GetFace(2).TextureID; + te2.CreateFace(12).TextureID = AgentTextureEntry.GetFace(12).TextureID; + te2.CreateFace(7).TextureID = AgentTextureEntry.GetFace(7).TextureID; + te2.CreateFace(6).TextureID = AgentTextureEntry.GetFace(6).TextureID; + te2.CreateFace(5).TextureID = AgentTextureEntry.GetFace(5).TextureID; + te2.CreateFace(4).TextureID = AgentTextureEntry.GetFace(4).TextureID; + te2.CreateFace(3).TextureID = AgentTextureEntry.GetFace(3).TextureID; + te2.CreateFace(1).TextureID = AgentTextureEntry.GetFace(1).TextureID; + te2.CreateFace(0).TextureID = AgentTextureEntry.GetFace(0).TextureID; + AgentTextureEntry = te2; + } + + private Dictionary GetAssetParamsAsVisualParams() + { + Dictionary VisualParams = new Dictionary(); + + float maxVal = 0; + float minVal = 0; + uint packetIdx = 0; + float range = 0; + float percentage = 0; + byte packetVal = 0; + + foreach (KeyValuePair kvp in AgentAppearanceParams) + { + packetIdx = AppearanceManager.GetAgentSetAppearanceIndex(kvp.Key) - 1; //TODO/FIXME: this should be zero indexed, not 1 based. + maxVal = BodyShapeParams.GetValueMax(kvp.Key); + minVal = BodyShapeParams.GetValueMin(kvp.Key); + + range = maxVal - minVal; + + percentage = (kvp.Value - minVal) / range; + + packetVal = (byte)(percentage * (byte)255); + + VisualParams[packetIdx] = packetVal; + } + + return VisualParams; + } + + private LLVector3 GetAgentSizeFromVisualParams(Dictionary VisualParams) + { + float AV_Height_Range = 2.025506f - 1.50856f; + float AV_Height = 1.50856f + (((float)VisualParams[25] / 255.0f) * AV_Height_Range); + return new LLVector3(0.45f, 0.6f, AV_Height); + } + + public void SendAgentSetAppearance() + { + // Get latest appearance info + if (AgentAppearanceParams.Count == 0) + { + GetAvatarAppearanceInfoFromWearableAssets(); + } + + AgentSetAppearancePacket p = new AgentSetAppearancePacket(); + p.AgentData.AgentID = Client.Network.AgentID; + p.AgentData.SessionID = Client.Network.SessionID; + p.AgentData.SerialNum = ++SerialNum; + + // Add Texture Data + p.ObjectData.TextureEntry = AgentTextureEntry.ToBytes(); + + // Add Visual Params + Dictionary VisualParams = GetAssetParamsAsVisualParams(); p.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[218]; for (uint i = 0; i < 218; i++) { @@ -240,33 +226,22 @@ namespace libsecondlife.AssetSystem uint paramid = GetParamID(i + 1); float defaultValue = BodyShapeParams.GetValueDefault(paramid); - maxVal = BodyShapeParams.GetValueMax(paramid); - minVal = BodyShapeParams.GetValueMin(paramid); + float minVal = BodyShapeParams.GetValueMin(paramid); - range = maxVal - minVal; + float range = BodyShapeParams.GetValueMax(paramid) - minVal; - percentage = (defaultValue - minVal) / range; + float percentage = (defaultValue - minVal) / range; - packetVal = (byte)(percentage * (byte)255); + byte packetVal = (byte)(percentage * (byte)255); - // Console.WriteLine("Warning Visual Param not defined, IDX: " + (i+1)); - // Console.WriteLine("PID: " + paramid + " / Default: " + defaultValue); p.VisualParam[i].ParamValue = packetVal; } } + // Add Size Data + p.AgentData.Size = GetAgentSizeFromVisualParams(VisualParams); + Client.Network.SendPacket(p); - - Console.WriteLine("Default: " + textures.DefaultTexture.TextureID); - - foreach (KeyValuePair kvp in textures.FaceTextures) - { - Console.WriteLine(kvp.Key + " : " + kvp.Value.TextureID); - } - - - - Console.WriteLine(p); } diff --git a/libsecondlife-cs/AssetSystem/AssetManager.cs b/libsecondlife-cs/AssetSystem/AssetManager.cs index ff333743..afecd09b 100644 --- a/libsecondlife-cs/AssetSystem/AssetManager.cs +++ b/libsecondlife-cs/AssetSystem/AssetManager.cs @@ -43,8 +43,6 @@ namespace libsecondlife.AssetSystem /// public class AssetManager { - private static Dictionary AssetManagers = new Dictionary(); - public const int SINK_FEE_IMAGE = 1; private SecondLife slClient; @@ -55,12 +53,13 @@ namespace libsecondlife.AssetSystem /// /// /// - private AssetManager(SecondLife client) + internal AssetManager(SecondLife client) { slClient = client; - // need to make sure we don't keep around old AssetManagers connected to stale instances of SL + // Need to know when we're Connected/Disconnected to clear state slClient.Network.OnDisconnected += new NetworkManager.DisconnectCallback(Network_OnDisconnected); + slClient.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); // Used to upload small assets, or as an initial start packet for large transfers slClient.Network.RegisterCallback(PacketType.AssetUploadComplete, new NetworkManager.PacketCallback(AssetUploadCompleteCallbackHandler)); @@ -72,30 +71,20 @@ namespace libsecondlife.AssetSystem slClient.Network.RegisterCallback(PacketType.RequestXfer, new NetworkManager.PacketCallback(RequestXferCallbackHandler)); } - void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message) + void Network_OnConnected(object sender) { - // Remove this asset manager from the managers list. - AssetManager.AssetManagers.Remove(this.slClient.Network.AgentID); + ClearState(); } - public static AssetManager GetAssetManager( SecondLife client ) + void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message) { - lock (AssetManagers) - { - if (AssetManagers.ContainsKey(client.Network.AgentID)) - { - AssetManager existingAssetManager = AssetManagers[client.Network.AgentID]; - if (existingAssetManager.slClient.Network.Connected == false) - { - existingAssetManager.slClient = client; - } - return existingAssetManager; - } else { - AssetManager am = new AssetManager(client); - AssetManagers[client.Network.AgentID] = am; - return am; - } - } + ClearState(); + } + + private void ClearState() + { + htDownloadRequests.Clear(); + curUploadRequest = null; } /// diff --git a/libsecondlife-cs/InventorySystem/InventoryFolder.cs b/libsecondlife-cs/InventorySystem/InventoryFolder.cs index 43b24a6a..3a59e857 100644 --- a/libsecondlife-cs/InventorySystem/InventoryFolder.cs +++ b/libsecondlife-cs/InventorySystem/InventoryFolder.cs @@ -9,6 +9,8 @@ namespace libsecondlife.InventorySystem /// public class InventoryFolder : InventoryBase { + public enum FolderUpdateFlag { None, NoRecurse, Recurse }; + public string Name { get { return _Name; } @@ -33,10 +35,10 @@ namespace libsecondlife.InventorySystem set { InventoryFolder ifParent = iManager.getFolder(this.ParentID); - ifParent.alContents.Remove(this); + ifParent._Contents.Remove(this); ifParent = iManager.getFolder(value); - ifParent.alContents.Add(this); + ifParent._Contents.Add(this); this._ParentID = value; @@ -50,7 +52,8 @@ namespace libsecondlife.InventorySystem get { return _Type; } } - public List alContents = new List(); + internal List _Contents = new List(); + internal InventoryFolder(InventoryManager manager) : base(manager) @@ -88,6 +91,29 @@ namespace libsecondlife.InventorySystem this._Type = sbyte.Parse(htData["type_default"].ToString()); } + /// + /// Get the contents of this folder + /// + /// Contents of this folder + public List GetContents() + { + return _Contents; + } + + /// + /// Request a download of this folder's content information. + /// + /// Indicate if we should recursively download content information. + /// The Request object for this download + public DownloadRequest_Folder BeginDownloadContents(bool recurse) + { + _Contents.Clear(); + + DownloadRequest_Folder dr = new DownloadRequest_Folder(FolderID, recurse); + iManager.RequestFolder(dr); + + return dr; + } public InventoryFolder CreateFolder(string name) { @@ -96,7 +122,7 @@ namespace libsecondlife.InventorySystem public void Delete() { - iManager.getFolder(this.ParentID).alContents.Remove(this); + iManager.getFolder(this.ParentID)._Contents.Remove(this); iManager.FolderRemove(this); } @@ -123,7 +149,7 @@ namespace libsecondlife.InventorySystem public List GetItemByName(string name) { List items = new List(); - foreach (InventoryBase ib in alContents) + foreach (InventoryBase ib in _Contents) { if (ib is InventoryFolder) { @@ -155,7 +181,7 @@ namespace libsecondlife.InventorySystem output += "Type = '" + Type + "' "; output += ">\n"; - foreach (Object oContent in alContents) + foreach (Object oContent in _Contents) { output += ((InventoryBase)oContent).toXML(outputAssets); } diff --git a/libsecondlife-cs/InventorySystem/InventoryItem.cs b/libsecondlife-cs/InventorySystem/InventoryItem.cs index cf1efc68..68460d9f 100644 --- a/libsecondlife-cs/InventorySystem/InventoryItem.cs +++ b/libsecondlife-cs/InventorySystem/InventoryItem.cs @@ -37,8 +37,8 @@ namespace libsecondlife.InventorySystem throw new Exception("Target Folder [" + value + "] does not exist."); } - base.iManager.getFolder(this.FolderID).alContents.Remove(this); - iTargetFolder.alContents.Add(this); + base.iManager.getFolder(this.FolderID)._Contents.Remove(this); + iTargetFolder._Contents.Add(this); _FolderID = value; UpdateItem(); @@ -422,7 +422,7 @@ namespace libsecondlife.InventorySystem /// public void Delete() { - base.iManager.getFolder(this.FolderID).alContents.Remove(this); + base.iManager.getFolder(this.FolderID)._Contents.Remove(this); base.iManager.ItemRemove(this); } diff --git a/libsecondlife-cs/InventorySystem/InventoryManager.cs b/libsecondlife-cs/InventorySystem/InventoryManager.cs index 6a98a292..3037c561 100644 --- a/libsecondlife-cs/InventorySystem/InventoryManager.cs +++ b/libsecondlife-cs/InventorySystem/InventoryManager.cs @@ -27,6 +27,7 @@ //#define DEBUG_PACKETS using System; +using System.Collections; using System.Collections.Generic; using System.Threading; @@ -46,6 +47,7 @@ namespace libsecondlife.InventorySystem // Reference to the SLClient Library private SecondLife slClient; + private ManualResetEvent InventoryManagerInitialized = new ManualResetEvent(false); // Reference to the Asset Manager private static AssetManager slAssetManager; @@ -56,15 +58,12 @@ namespace libsecondlife.InventorySystem public InventoryPacketHelper InvPacketHelper = null; - // UUID of Root Inventory Folder - private LLUUID uuidRootFolder; - // Setup a dictionary to easily lookup folders by UUID private Dictionary htFoldersByUUID = new Dictionary(); // Setup a dictionary to track download progress - private Dictionary htFolderDownloadStatus; - private List alFolderRequestQueue; + private Dictionary FolderDownloadStatus = new Dictionary(); + private List alFolderRequestQueue = new List(); // Used to track current item being created private InventoryItem iiCreationInProgress; @@ -73,19 +72,16 @@ namespace libsecondlife.InventorySystem private int LastPacketRecievedAtTick; // Each InventorySystem needs to be initialized with a client and root folder. - public InventoryManager(SecondLife client, LLUUID rootFolder) + public InventoryManager(SecondLife client) { slClient = client; - if (slAssetManager == null) - { - slAssetManager = AssetManager.GetAssetManager(slClient); - } + slAssetManager = slClient.Assets; - InvPacketHelper = new InventoryPacketHelper(slClient.Network.AgentID, slClient.Network.SessionID); + InvPacketHelper = new InventoryPacketHelper(slClient); - uuidRootFolder = rootFolder; - - resetFoldersByUUID(); + // Need to know what when we're connected/disconnected + slClient.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); + slClient.Network.OnDisconnected += new NetworkManager.DisconnectCallback(Network_OnDisconnected); // Setup the callback for Inventory Downloads slClient.Network.RegisterCallback(PacketType.InventoryDescendents, new NetworkManager.PacketCallback(InventoryDescendentsHandler)); @@ -95,25 +91,35 @@ namespace libsecondlife.InventorySystem } - // Used primarily for debugging and testing - public AssetManager getAssetManager() + void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message) { - // Console.WriteLine("It is not recommended that you access the asset manager directly"); - return AssetManager; + // Clear out current state + ClearState(); } - private void resetFoldersByUUID() + void Network_OnConnected(object sender) { - // Init folder structure with root - htFoldersByUUID = new Dictionary(); + // Clear out current state + ClearState(); + } - InventoryFolder ifRootFolder = new InventoryFolder(this, "My Inventory", uuidRootFolder, null); - htFoldersByUUID[uuidRootFolder] = ifRootFolder; + private void ClearState() + { + htFoldersByUUID.Clear(); + FolderDownloadStatus.Clear(); + alFolderRequestQueue.Clear(); + + if (slClient.Self.InventoryRootFolderUUID != null) + { + // Init folder structure with root + InventoryFolder ifRootFolder = new InventoryFolder(this, "My Inventory", slClient.Self.InventoryRootFolderUUID, null); + htFoldersByUUID[slClient.Self.InventoryRootFolderUUID] = ifRootFolder; + } } public InventoryFolder getRootFolder() { - return htFoldersByUUID[uuidRootFolder]; + return htFoldersByUUID[slClient.Self.InventoryRootFolderUUID]; } public InventoryFolder getFolder(LLUUID folderID) @@ -157,7 +163,7 @@ namespace libsecondlife.InventorySystem { string sCurFolder = qFolderPath.Dequeue(); - foreach (InventoryBase ibFolder in ifRoot.alContents) + foreach (InventoryBase ibFolder in ifRoot._Contents) { if (ibFolder is libsecondlife.InventorySystem.InventoryFolder) { @@ -178,14 +184,18 @@ namespace libsecondlife.InventorySystem return null; } - private void RequestFolder(DescendentRequest dr) + /// + /// + /// + /// + internal void RequestFolder(DownloadRequest_Folder dr) { Packet packet = InvPacketHelper.FetchInventoryDescendents( dr.FolderID , dr.FetchFolders , dr.FetchItems); - htFolderDownloadStatus[dr.FolderID] = dr; + FolderDownloadStatus[dr.FolderID] = dr; slClient.Network.SendPacket(packet); } @@ -197,10 +207,10 @@ namespace libsecondlife.InventorySystem if (htFoldersByUUID.ContainsKey(ifolder.ParentID)) { - if (((InventoryFolder)htFoldersByUUID[ifolder.ParentID]).alContents.Contains(ifolder) == false) + if (((InventoryFolder)htFoldersByUUID[ifolder.ParentID])._Contents.Contains(ifolder) == false) { // Add new folder to the contents of the parent folder. - ((InventoryFolder)htFoldersByUUID[ifolder.ParentID]).alContents.Add(ifolder); + ((InventoryFolder)htFoldersByUUID[ifolder.ParentID])._Contents.Add(ifolder); } } else @@ -317,7 +327,7 @@ namespace libsecondlife.InventorySystem internal void ItemRemove(InventoryItem iitem) { InventoryFolder ifolder = getFolder(iitem.FolderID); - ifolder.alContents.Remove(iitem); + ifolder._Contents.Remove(iitem); Packet packet = InvPacketHelper.RemoveInventoryItem(iitem.ItemID); slClient.Network.SendPacket(packet); @@ -359,16 +369,16 @@ namespace libsecondlife.InventorySystem public void DownloadInventory() { - resetFoldersByUUID(); + ClearState(); - if (htFolderDownloadStatus == null) + if (FolderDownloadStatus == null) { // Create status table - htFolderDownloadStatus = new Dictionary(); + FolderDownloadStatus = new Dictionary(); } else { - if (htFolderDownloadStatus.Count != 0) + if (FolderDownloadStatus.Count != 0) { throw new Exception("Inventory Download requested while previous download in progress."); } @@ -376,7 +386,7 @@ namespace libsecondlife.InventorySystem if (alFolderRequestQueue == null) { - alFolderRequestQueue = new List(); + alFolderRequestQueue = new List(); } // Set last packet received to now, just so out time-out timer works @@ -384,13 +394,13 @@ namespace libsecondlife.InventorySystem // Send Packet requesting the root Folder, // this should recurse through all folders - RequestFolder(new DescendentRequest(uuidRootFolder)); + RequestFolder(new DownloadRequest_Folder(slClient.Self.InventoryRootFolderUUID)); - while ((htFolderDownloadStatus.Count > 0) || (alFolderRequestQueue.Count > 0)) + while ((FolderDownloadStatus.Count > 0) || (alFolderRequestQueue.Count > 0)) { - if (htFolderDownloadStatus.Count == 0) + if (FolderDownloadStatus.Count == 0) { - DescendentRequest dr = alFolderRequestQueue[0]; + DownloadRequest_Folder dr = alFolderRequestQueue[0]; alFolderRequestQueue.RemoveAt(0); RequestFolder(dr); } @@ -403,14 +413,14 @@ namespace libsecondlife.InventorySystem // have to make a seperate list otherwise we run into modifying the original array // while still enumerating it. - List alRestartList = new List(); + List alRestartList = new List(); - //if (htFolderDownloadStatus[0] != null) + //if (FolderDownloadStatus[0] != null) //{ - // Console.WriteLine(htFolderDownloadStatus[0].GetType()); + // Console.WriteLine(FolderDownloadStatus[0].GetType()); //} - foreach (DescendentRequest dr in htFolderDownloadStatus.Values) + foreach (DownloadRequest_Folder dr in FolderDownloadStatus.Values) { Console.WriteLine(dr.FolderID + " " + dr.Expected + " / " + dr.Received + " / " + dr.LastReceivedAtTick); @@ -418,7 +428,7 @@ namespace libsecondlife.InventorySystem } LastPacketRecievedAtTick = Environment.TickCount; - foreach (DescendentRequest dr in alRestartList) + foreach (DownloadRequest_Folder dr in alRestartList) { RequestFolder(dr); } @@ -477,21 +487,36 @@ namespace libsecondlife.InventorySystem } } - + /// + /// Returned in response to a InventoryDescendantRequest. Contains information about the + /// contents of a folder. + /// + /// + /// + /// public void InventoryDescendentsHandler(Packet packet, Simulator simulator) { InventoryDescendentsPacket reply = (InventoryDescendentsPacket)packet; + // The UUID of this folder. + LLUUID uuidFolderID = reply.AgentData.FolderID; + + // Get the original Descendent Request for this Packet + DownloadRequest_Folder dr = (DownloadRequest_Folder)FolderDownloadStatus[uuidFolderID]; + + // Update Inventory Manager's last tick point, used for timeouts and such LastPacketRecievedAtTick = Environment.TickCount; + // Some temp variables to be reused as we're parsing the packet InventoryItem invItem; InventoryFolder invFolder; - LLUUID uuidFolderID = LLUUID.Zero; - - int iDescendentsExpected = int.MaxValue; + // Used to count the number of descendants received to see if we're finished or not. + int iDescendentsExpected = reply.AgentData.Descendents; int iDescendentsReceivedThisBlock = 0; + + foreach (InventoryDescendentsPacket.ItemDataBlock itemBlock in reply.ItemData) { // There is always an item block, even if there isn't any items @@ -502,8 +527,8 @@ namespace libsecondlife.InventorySystem if (itemBlock.ItemID == LLUUID.Zero) { - // this shouldn't ever happen, but unless you've uploaded an invalid item - // to yourself while developping inventory code + // this shouldn't ever happen, unless you've uploaded an invalid item + // to yourself while developping inventory code :-( } else { @@ -511,7 +536,7 @@ namespace libsecondlife.InventorySystem InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invItem.FolderID]; - if (ifolder.alContents.Contains(invItem) == false) + if (ifolder._Contents.Contains(invItem) == false) { if ((invItem.InvType == 7) && (invItem.Type == Asset.ASSET_TYPE_NOTECARD)) { @@ -525,7 +550,7 @@ namespace libsecondlife.InventorySystem invItem = temp; } - ifolder.alContents.Add(invItem); + ifolder._Contents.Add(invItem); } } } @@ -549,9 +574,9 @@ namespace libsecondlife.InventorySystem // Add folder to Parent InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invFolder.ParentID]; - if (ifolder.alContents.Contains(invFolder) == false) + if (ifolder._Contents.Contains(invFolder) == false) { - ifolder.alContents.Add(invFolder); + ifolder._Contents.Add(invFolder); } @@ -559,45 +584,45 @@ namespace libsecondlife.InventorySystem htFoldersByUUID[invFolder.FolderID] = invFolder; - // It's not the root, should be safe to "recurse" - if (!invFolder.FolderID.Equals(uuidRootFolder)) + // Do we recurse? + if (dr.Recurse) { - bool alreadyQueued = false; - foreach (DescendentRequest dr in alFolderRequestQueue) + // It's not the root, should be safe to "recurse" + if (!invFolder.FolderID.Equals(slClient.Self.InventoryRootFolderUUID)) { - if (dr.FolderID == invFolder.FolderID) + bool alreadyQueued = false; + foreach (DownloadRequest_Folder adr in alFolderRequestQueue) { - alreadyQueued = true; - break; + if (adr.FolderID == invFolder.FolderID) + { + alreadyQueued = true; + break; + } } - } - if (!alreadyQueued) - { - alFolderRequestQueue.Add(new DescendentRequest(invFolder.FolderID)); + if (!alreadyQueued) + { + alFolderRequestQueue.Add(new DownloadRequest_Folder(invFolder.FolderID)); + } } } } } - // Check how many descendents we're actually supposed to receive - iDescendentsExpected = reply.AgentData.Descendents; - uuidFolderID = reply.AgentData.FolderID; // Update download status for this folder if (iDescendentsReceivedThisBlock >= iDescendentsExpected) { // We received all the descendents we're expecting for this folder // in this packet, so go ahead and remove folder from status list. - htFolderDownloadStatus.Remove(uuidFolderID); + FolderDownloadStatus.Remove(uuidFolderID); + dr.RequestComplete.Set(); } else { // This one packet didn't have all the descendents we're expecting // so update the total we're expecting, and update the total downloaded - - DescendentRequest dr = (DescendentRequest)htFolderDownloadStatus[uuidFolderID]; dr.Expected = iDescendentsExpected; dr.Received += iDescendentsReceivedThisBlock; dr.LastReceivedAtTick = Environment.TickCount; @@ -606,41 +631,15 @@ namespace libsecondlife.InventorySystem { // Looks like after updating, we have all the descendents, // remove from folder status. - htFolderDownloadStatus.Remove(uuidFolderID); + FolderDownloadStatus.Remove(uuidFolderID); + dr.RequestComplete.Set(); } else { - htFolderDownloadStatus[uuidFolderID] = dr; + FolderDownloadStatus[uuidFolderID] = dr; // Console.WriteLine( uuidFolderID + " is expecting " + (iDescendentsExpected - iStatus[1]) + " more packets." ); } } } - - private class DescendentRequest - { - public LLUUID FolderID; - - public int Expected = int.MaxValue; - public int Received = 0; - public int LastReceivedAtTick = 0; - - public bool FetchFolders = true; - public bool FetchItems = true; - - public DescendentRequest(LLUUID folderID) - { - FolderID = folderID; - LastReceivedAtTick = Environment.TickCount; - } - - public DescendentRequest(LLUUID folderID, bool fetchFolders, bool fetchItems) - { - FolderID = folderID; - FetchFolders = fetchFolders; - FetchItems = fetchItems; - LastReceivedAtTick = Environment.TickCount; - } - - } } } diff --git a/libsecondlife-cs/InventorySystem/InventoryPacketHelper.cs b/libsecondlife-cs/InventorySystem/InventoryPacketHelper.cs index 9e44d525..7ee49e21 100644 --- a/libsecondlife-cs/InventorySystem/InventoryPacketHelper.cs +++ b/libsecondlife-cs/InventorySystem/InventoryPacketHelper.cs @@ -11,13 +11,21 @@ namespace libsecondlife.InventorySystem /// public class InventoryPacketHelper { - private LLUUID AgentID; - private LLUUID SessionID; + private SecondLife Client; - public InventoryPacketHelper(LLUUID AgentID, LLUUID SessionID) + private LLUUID AgentID + { + get { return Client.Network.AgentID; } + } + + private LLUUID SessionID + { + get { return Client.Network.SessionID; } + } + + public InventoryPacketHelper(SecondLife client) { - this.AgentID = AgentID; - this.SessionID = SessionID; + Client = client; } public const int FETCH_INVENTORY_SORT_NAME = 0; diff --git a/libsecondlife-cs/MainAvatar.cs b/libsecondlife-cs/MainAvatar.cs index 3fb04e2c..6945c251 100644 --- a/libsecondlife-cs/MainAvatar.cs +++ b/libsecondlife-cs/MainAvatar.cs @@ -175,6 +175,9 @@ namespace libsecondlife public LLVector3 HomeLookAt = LLVector3.Zero; /// Used for camera and control key state tracking public MainAvatarStatus Status; + /// The UUID of your root inventory folder + public LLUUID InventoryRootFolderUUID; + /// Gets the health of the agent public float Health diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs index 544a2e11..cd947577 100644 --- a/libsecondlife-cs/NetworkManager.cs +++ b/libsecondlife-cs/NetworkManager.cs @@ -1154,6 +1154,13 @@ namespace libsecondlife Client.Self.HomePosition = posVector; Client.Self.HomeLookAt = lookatVector; + // Get Inventory Root Folder + Client.Log("Pulling root folder UUID from login data.", Helpers.LogLevel.Debug); + ArrayList alInventoryRoot = (ArrayList)LoginValues["inventory-root"]; + Hashtable htInventoryRoot = (Hashtable)alInventoryRoot[0]; + Client.Self.InventoryRootFolderUUID = new LLUUID((string)htInventoryRoot["folder_id"]); + + // Connect to the sim given in the login reply Simulator simulator = new Simulator(Client, this.Callbacks, (uint)(int)LoginValues["circuit_code"], IPAddress.Parse((string)LoginValues["sim_ip"]), (int)LoginValues["sim_port"]); diff --git a/libsecondlife-cs/SecondLife.cs b/libsecondlife-cs/SecondLife.cs index 5ef30591..7564068b 100644 --- a/libsecondlife-cs/SecondLife.cs +++ b/libsecondlife-cs/SecondLife.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using libsecondlife.Packets; using libsecondlife.AssetSystem; +using libsecondlife.InventorySystem; namespace libsecondlife { @@ -60,34 +61,19 @@ namespace libsecondlife public ObjectManager Objects; /// Group Subsystem public GroupManager Groups; + + /// Asset Subsystem + public AssetManager Assets; + /// Inventory Subsystem + public InventoryManager Inventory; + /// Image Subsystem + public ImageManager Images; + /// Throttling Subsystem public AgentThrottle Throttle; /// Settings Subsystem public Settings Settings; - private ImageManager _ImageManager; - /// Image Subsystem - public ImageManager Images - { - get - { - if (_ImageManager == null) - { - _ImageManager = new ImageManager(this); - return _ImageManager; - } - else - { - return _ImageManager; - } - } - - set - { - _ImageManager = value; - } - } - /// Triggered whenever a message is logged. /// If this is left null, log messages will go to /// the console @@ -107,6 +93,11 @@ namespace libsecondlife Grid = new GridManager(this); Objects = new ObjectManager(this); Groups = new GroupManager(this); + + Assets = new AssetManager(this); + Images = new ImageManager(this); + Inventory = new InventoryManager(this); + Throttle = new AgentThrottle(this); Settings = new Settings(this); } diff --git a/libsecondlife-cs/examples/IA_ImageTool/ImageTool.cs b/libsecondlife-cs/examples/IA_ImageTool/ImageTool.cs index d66095c4..1910f9dc 100644 --- a/libsecondlife-cs/examples/IA_ImageTool/ImageTool.cs +++ b/libsecondlife-cs/examples/IA_ImageTool/ImageTool.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading; using IA_SimpleInventory; @@ -13,8 +14,12 @@ namespace IA_ImageTool /// /// Summary description for Class1. /// - class ImageTool : SimpleInventory + class ImageTool { + private SecondLife _Client; + private ManualResetEvent ConnectedSignal = new ManualResetEvent(false); + + private List _ImageIDs = new List(); private string _FileName; private bool _Put; @@ -24,7 +29,7 @@ namespace IA_ImageTool /// Used to upload/download images. /// [STAThread] - static new void Main(string[] args) + static void Main(string[] args) { if ( (File.Exists("libjasper.dll") == false) ) { @@ -94,17 +99,16 @@ namespace IA_ImageTool ImageTool it = new ImageTool(uuidList, filename, put, rate); - // Only download the inventory tree if we're planning on putting/uploading files. - it.DownloadInventoryOnConnect = put; if (it.Connect(args[0], args[1], args[2])) { - it.doStuff(); - it.Disconnect(); + if (it.ConnectedSignal.WaitOne(TimeSpan.FromMinutes(1), false)) + { + it.doStuff(); - System.Threading.Thread.Sleep(500); + it.Disconnect(); + } - Console.WriteLine("Done logging out."); } } @@ -114,12 +118,62 @@ namespace IA_ImageTool _FileName = filename; _Put = put; _Rate = rate; + + try + { + _Client = new SecondLife(); + _Client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); + } + catch (Exception e) + { + // Error initializing the client + Console.WriteLine(); + Console.WriteLine(e.ToString()); + } + } - protected new void doStuff() + void Network_OnConnected(object sender) + { + ConnectedSignal.Set(); + } + + protected bool Connect(string FirstName, string LastName, string Password) + { + Console.WriteLine("Attempting to connect and login to SecondLife."); + + // Setup Login to Second Life + Dictionary loginReply = new Dictionary(); + + // Login + if (!_Client.Network.Login(FirstName, LastName, Password, "ImageTool", "static.sprocket@gmail.com")) + { + // Login failed + Console.WriteLine("Error logging in: " + _Client.Network.LoginError); + return false; + } + + // Login was successful + Console.WriteLine("Login was successful."); + Console.WriteLine("AgentID: " + _Client.Network.AgentID); + Console.WriteLine("SessionID: " + _Client.Network.SessionID); + + return true; + } + + protected void Disconnect() + { + // Logout of Second Life + Console.WriteLine("Request logout"); + _Client.Network.Logout(); + } + + protected void doStuff() { if (_Put) { + + Console.WriteLine("Reading: " + _FileName); byte[] j2cdata; @@ -135,7 +189,7 @@ namespace IA_ImageTool Console.WriteLine("Connecting to your Texture folder..."); - InventoryFolder iFolder = AgentInventory.getFolder("Textures"); + InventoryFolder iFolder = _Client.Inventory.getFolder("Textures"); Console.WriteLine("Uploading Texture..."); InventoryImage image = iFolder.NewImage(_FileName, "ImageTool Upload", j2cdata); @@ -162,7 +216,7 @@ namespace IA_ImageTool try { - j2cdata = client.Images.RequestImage(ImageID); + j2cdata = _Client.Images.RequestImage(ImageID); int end = Environment.TickCount; Console.WriteLine("Elapsed download time, in TickCounts: " + (end - start)); diff --git a/libsecondlife-cs/examples/IA_InventoryManager/iManager.cs b/libsecondlife-cs/examples/IA_InventoryManager/iManager.cs index 463dd18c..f7303e44 100644 --- a/libsecondlife-cs/examples/IA_InventoryManager/iManager.cs +++ b/libsecondlife-cs/examples/IA_InventoryManager/iManager.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text; +using System.Threading; using System.Xml; using System.Xml.Serialization; @@ -23,7 +25,7 @@ namespace IA_InventoryManager /// * MOVE /// * GIVE /// - class iManager : SimpleInventory + class iManager { private char[] cmdSeperators = { ' ' }; private string curDirectory = "/"; @@ -31,9 +33,12 @@ namespace IA_InventoryManager private string TYPE_DIR = " "; private string TYPE_ITEM = " "; + private SecondLife _Client; private AppearanceManager aManager; - static new void Main(string[] args) + private ManualResetEvent ConnectedSignal = new ManualResetEvent(false); + + static void Main(string[] args) { if (args.Length < 3) { @@ -42,18 +47,35 @@ namespace IA_InventoryManager } iManager it = new iManager(); - it.Connect(args[0], args[1], args[2]); - it.doStuff(); - it.Disconnect(); + if (it.Connect(args[0], args[1], args[2])) + { + if (it.ConnectedSignal.WaitOne(TimeSpan.FromMinutes(1), false)) + { + it.doStuff(); + it.Disconnect(); + } + } + } - System.Threading.Thread.Sleep(1000); + public iManager() + { + try + { + _Client = new SecondLife(); + _Client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); + _Client.Self.OnTeleport += new TeleportCallback(Self_OnTeleport); + } + catch (Exception e) + { + // Error initializing the client + Console.WriteLine(); + Console.WriteLine(e.ToString()); + } } - private new void doStuff() + private void doStuff() { - client.Self.OnTeleport += new TeleportCallback(Self_OnTeleport); - System.Threading.Thread.Sleep(1000); Console.WriteLine("=================================================================="); @@ -164,6 +186,17 @@ namespace IA_InventoryManager getlook(); break; + case "saveav": + saveavatar(curCmdLine); + break; + + case "savew": + savewearables(curCmdLine); + break; + + case "loadw": + loadwearables(curCmdLine); + break; default: Console.WriteLine("Unknown command '" + curCmdLine[0] + "'."); @@ -192,10 +225,144 @@ namespace IA_InventoryManager Console.WriteLine("REGIONINFO - Display Grid Region Info."); Console.WriteLine("TELEPORT - Teleport to a new sim."); Console.WriteLine("NOTECARD - Create a new notecard."); - Console.WriteLine("XML - Display an item as xml"); + Console.WriteLine("XML - Display an item as xml."); + Console.WriteLine("GETLOOK - Send an AgentSetAppearance based on your current weables."); + Console.WriteLine("SAVEAV - Serialize your current wearables and the info from them."); + Console.WriteLine("SAVEW - Serialize your current wearables."); + Console.WriteLine("LOADW - Load a previously serialized wearables."); Console.WriteLine("QUIT - Exit the Inventory Manager."); } + private void savewearables(string[] cmdLine) + { + if (aManager == null) + { + aManager = new AppearanceManager(_Client); + } + + // Get Wearable Data + AgentWearablesUpdatePacket.WearableDataBlock[] wdbs = aManager.GetWearables(); + List WearablesList = new List(); + foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in wdbs) + { + WearablesList.Add(wdb); + } + + // Serialize to XML + StringBuilder sb = new StringBuilder(); + XmlWriterSettings xmlws = new XmlWriterSettings(); + xmlws.Indent = true; + XmlWriter xmlw = XmlWriter.Create(sb, xmlws); + XmlSerializer serializer = new XmlSerializer(typeof(List)); + serializer.Serialize(xmlw, WearablesList); + + // Output + if (cmdLine.Length >= 2) + { + Console.WriteLine("Writing wearable data to : " + cmdLine[1]); + + File.WriteAllText(cmdLine[1], sb.ToString()); + + Console.WriteLine("Done..."); + } + else + { + Console.WriteLine(sb.ToString()); + } + } + + private void loadwearables(string[] cmdLine) + { + if (cmdLine.Length < 2) + { + Console.WriteLine("You must specify the file to load the wearables from."); + Console.WriteLine("Usage: loadw [file.xml]"); + return; + } + + Console.WriteLine("Reading Wearable data from: " + cmdLine[1]); + + try + { + XmlReader xmlr = XmlReader.Create(File.OpenText(cmdLine[1])); + + XmlSerializer serializer = new XmlSerializer(typeof(List)); + List WearablesList = (List)serializer.Deserialize(xmlr); + + foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in WearablesList) + { + Console.WriteLine(wdb.AssetID); + } + + } + catch (Exception e) + { + Console.WriteLine("An error has occured..."); + Console.WriteLine(e.Message); + Console.WriteLine(e.StackTrace); + } + + } + + private void saveavatar(string[] cmdLine) + { + if (aManager == null) + { + aManager = new AppearanceManager(_Client); + } + + AgentWearablesUpdatePacket.WearableDataBlock[] wdbs = aManager.GetWearables(); + aManager.GetAvatarAppearanceInfoFromWearableAssets(); + + // Get the list of wearables + + List WearablesList = new List(); + foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in wdbs) + { + WearablesList.Add(wdb); + } + + XmlWriterSettings xmlws = new XmlWriterSettings(); + xmlws.OmitXmlDeclaration = true; + xmlws.Indent = true; + xmlws.CloseOutput = false; + + StringBuilder Save = new StringBuilder(); + Save.Append(""); + + // Wearables + StringBuilder sb = new StringBuilder(); + XmlWriter xmlw = XmlWriter.Create(sb, xmlws); + XmlSerializer serializer = new XmlSerializer(typeof(List)); + serializer.Serialize(xmlw, WearablesList); + + Save.AppendLine(sb.ToString()); + + // Parameters + sb = new StringBuilder(); + xmlw = XmlWriter.Create(sb, xmlws); + serializer = new XmlSerializer(typeof(SerializableDictionary)); + serializer.Serialize(xmlw, aManager.AgentAppearanceParams); + + Save.AppendLine(sb.ToString()); + + // Parameters + sb = new StringBuilder(); + xmlw = XmlWriter.Create(sb, xmlws); + serializer = new XmlSerializer(typeof(TextureEntry)); + serializer.Serialize(xmlw, aManager.AgentTextureEntry); + + Save.AppendLine(sb.ToString()); + + // Finish off save data + Save.Append(""); + + Console.WriteLine(Save.ToString()); + + //aManager.SendAgentSetAppearance + + } + private void StandUpStraight() { AgentUpdatePacket p = new AgentUpdatePacket(); @@ -206,17 +373,17 @@ namespace IA_InventoryManager p.AgentData.CameraUpAxis = new LLVector3(0, 0, 0); p.AgentData.HeadRotation = new LLQuaternion(0, 0, 0, 1); ; p.AgentData.BodyRotation = new LLQuaternion(0, 0, 0, 1); ; - p.AgentData.AgentID = client.Network.AgentID; - p.AgentData.SessionID = client.Network.SessionID; + p.AgentData.AgentID = _Client.Network.AgentID; + p.AgentData.SessionID = _Client.Network.SessionID; p.AgentData.ControlFlags = (uint)Avatar.AgentUpdateFlags.AGENT_CONTROL_STAND_UP; - client.Network.SendPacket(p); + _Client.Network.SendPacket(p); } private void getlook() { if (aManager == null) { - aManager = new AppearanceManager(client); + aManager = new AppearanceManager(_Client); } @@ -242,17 +409,20 @@ namespace IA_InventoryManager { } - InventoryFolder iFolder = AgentInventory.getFolder(curDirectory); + InventoryFolder iFolder = _Client.Inventory.getFolder(curDirectory); InventoryBase itemOfInterest = null; - foreach (InventoryBase ib in iFolder.alContents) + iFolder.BeginDownloadContents(false).RequestComplete.WaitOne(15000,false); + foreach (InventoryBase ib in iFolder.GetContents()) { if (ib is InventoryFolder) { InventoryFolder folder = (InventoryFolder)ib; if (folder.Name.Equals(cmdLine[1]) || folder.FolderID.Equals(uuid)) { + // Refresh the folder tree for this folder before outputing it. + folder.BeginDownloadContents(true).RequestComplete.WaitOne(30000, false); itemOfInterest = folder; break; } @@ -309,7 +479,7 @@ namespace IA_InventoryManager sb.Append(cki.Key.ToString()); } while (cki.Key != ConsoleKey.Escape); - InventoryFolder iFolder = AgentInventory.getFolder(curDirectory); + InventoryFolder iFolder = _Client.Inventory.getFolder(curDirectory); iFolder.NewNotecard(cmdLine[1], NoteDesc, sb.ToString()); Console.WriteLine("Notecard '" + NoteName + " 'Created"); @@ -324,22 +494,22 @@ namespace IA_InventoryManager return; } - if (cmdLine[1].ToLower() == client.Network.CurrentSim.Region.Name.ToLower()) + if (cmdLine[1].ToLower() == _Client.Network.CurrentSim.Region.Name.ToLower()) { Console.WriteLine("TODO: Add the ability to teleport somewhere in the local region. " + "Exiting for now, please specify a region other than the current one"); } else { - if (client.Grid.Regions.Count == 0) + if (_Client.Grid.Regions.Count == 0) { Console.WriteLine("Caching estate sims..."); - client.Grid.AddEstateSims(); + _Client.Grid.AddEstateSims(); System.Threading.Thread.Sleep(3000); } - - client.Self.Teleport(cmdLine[1], new LLVector3( float.Parse(cmdLine[2]), float.Parse(cmdLine[3]), float.Parse(cmdLine[4]) ) ); + + _Client.Self.Teleport(cmdLine[1], new LLVector3(float.Parse(cmdLine[2]), float.Parse(cmdLine[3]), float.Parse(cmdLine[4]))); } } @@ -360,7 +530,7 @@ namespace IA_InventoryManager } regionName = regionName.Trim(); - GridRegion gr = client.Grid.GetGridRegion(regionName); + GridRegion gr = _Client.Grid.GetGridRegion(regionName); Console.WriteLine(gr); } @@ -382,15 +552,17 @@ namespace IA_InventoryManager // Arbitrary Asset Asset asset = new Asset(cmdLine[2], sbyte.Parse(cmdLine[1]), null); - AgentInventory.getAssetManager().GetInventoryAsset(asset); + _Client.Assets.GetInventoryAsset(asset); Console.WriteLine(asset.AssetDataToString()); } else { // Asset for an item in inventory - InventoryFolder iFolder = AgentInventory.getFolder(curDirectory); - foreach (InventoryBase ib in iFolder.alContents) + InventoryFolder iFolder = _Client.Inventory.getFolder(curDirectory); + + iFolder.BeginDownloadContents(false).RequestComplete.WaitOne(15000, false); + foreach (InventoryBase ib in iFolder.GetContents()) { if (ib is InventoryItem) { @@ -423,7 +595,7 @@ namespace IA_InventoryManager } targetDir += combineCmdArg(cmdLine); - InventoryFolder iFolder = AgentInventory.getFolder(targetDir); + InventoryFolder iFolder = _Client.Inventory.getFolder(targetDir); if (iFolder == null) { Console.WriteLine("Could not find directory: " + targetDir); @@ -446,7 +618,7 @@ namespace IA_InventoryManager string targetDir = combineCmdArg(cmdLine); - InventoryFolder iFolder = AgentInventory.getFolder(curDirectory); + InventoryFolder iFolder = _Client.Inventory.getFolder(curDirectory); InventoryFolder newFolder = iFolder.CreateFolder(targetDir); @@ -492,7 +664,7 @@ namespace IA_InventoryManager Console.WriteLine("Changing directory to: " + targetDir ); - InventoryFolder iFolder = AgentInventory.getFolder(targetDir); + InventoryFolder iFolder = _Client.Inventory.getFolder(targetDir); if (iFolder == null) { @@ -521,8 +693,9 @@ namespace IA_InventoryManager Console.WriteLine(".."); } - InventoryFolder iFolder = AgentInventory.getFolder(curDirectory); - foreach (InventoryBase ib in iFolder.alContents) + InventoryFolder iFolder = _Client.Inventory.getFolder(curDirectory); + iFolder.BeginDownloadContents(false).RequestComplete.WaitOne(15000, false); + foreach (InventoryBase ib in iFolder.GetContents()) { if (ib is InventoryFolder) { @@ -550,5 +723,41 @@ namespace IA_InventoryManager } return rtn.Trim(); } + + void Network_OnConnected(object sender) + { + ConnectedSignal.Set(); + } + + protected bool Connect(string FirstName, string LastName, string Password) + { + Console.WriteLine("Attempting to connect and login to SecondLife."); + + // Setup Login to Second Life + Dictionary loginReply = new Dictionary(); + + // Login + if (!_Client.Network.Login(FirstName, LastName, Password, "createnotecard", "static.sprocket@gmail.com")) + { + // Login failed + Console.WriteLine("Error logging in: " + _Client.Network.LoginError); + return false; + } + + // Login was successful + Console.WriteLine("Login was successful."); + Console.WriteLine("AgentID: " + _Client.Network.AgentID); + Console.WriteLine("SessionID: " + _Client.Network.SessionID); + + return true; + } + + protected void Disconnect() + { + // Logout of Second Life + Console.WriteLine("Request logout"); + _Client.Network.Logout(); + } + } } diff --git a/libsecondlife-cs/examples/IA_MultiImageUpload/MultiImageUpload.cs b/libsecondlife-cs/examples/IA_MultiImageUpload/MultiImageUpload.cs index e82634f1..65be6892 100644 --- a/libsecondlife-cs/examples/IA_MultiImageUpload/MultiImageUpload.cs +++ b/libsecondlife-cs/examples/IA_MultiImageUpload/MultiImageUpload.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading; using IA_SimpleInventory; using IA_ImageTool; @@ -11,11 +12,14 @@ using libsecondlife.AssetSystem; namespace IA_MultiImageUpload { - class MultiImageUpload : SimpleInventory + class MultiImageUpload { + private SecondLife _Client; + private ManualResetEvent ConnectedSignal = new ManualResetEvent(false); + protected string ImageDirectory; - static new void Main(string[] args) + static void Main(string[] args) { if (args.Length < 4) { @@ -32,14 +36,31 @@ namespace IA_MultiImageUpload } MultiImageUpload app = new MultiImageUpload( fullpath ); - app.Connect(args[0], args[1], args[2]); - app.doStuff(); - app.Disconnect(); + if (app.Connect(args[0], args[1], args[2])) + { + if (app.ConnectedSignal.WaitOne(TimeSpan.FromMinutes(1), false)) + { + app.doStuff(); + app.Disconnect(); + } + } } public MultiImageUpload(string dir) { ImageDirectory = dir; + try + { + _Client = new SecondLife(); + _Client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); + } + catch (Exception e) + { + // Error initializing the client + Console.WriteLine(); + Console.WriteLine(e.ToString()); + } + } public static void Usage() @@ -47,9 +68,9 @@ namespace IA_MultiImageUpload System.Console.WriteLine("MultiImageUpload [FirstName] [LastName] [Password] [Directory]"); } - protected new void doStuff() + protected void doStuff() { - InventoryFolder iFolder = AgentInventory.getFolder("Textures"); + InventoryFolder iFolder = _Client.Inventory.getFolder("Textures"); iFolder = iFolder.CreateFolder(Helpers.GetUnixTime().ToString()); Console.WriteLine("Uploading images:"); @@ -79,5 +100,39 @@ namespace IA_MultiImageUpload } } } + void Network_OnConnected(object sender) + { + ConnectedSignal.Set(); + } + + protected bool Connect(string FirstName, string LastName, string Password) + { + Console.WriteLine("Attempting to connect and login to SecondLife."); + + // Setup Login to Second Life + Dictionary loginReply = new Dictionary(); + + // Login + if (!_Client.Network.Login(FirstName, LastName, Password, "MultiImageUpload", "static.sprocket@gmail.com")) + { + // Login failed + Console.WriteLine("Error logging in: " + _Client.Network.LoginError); + return false; + } + + // Login was successful + Console.WriteLine("Login was successful."); + Console.WriteLine("AgentID: " + _Client.Network.AgentID); + Console.WriteLine("SessionID: " + _Client.Network.SessionID); + + return true; + } + + protected void Disconnect() + { + // Logout of Second Life + Console.WriteLine("Request logout"); + _Client.Network.Logout(); + } } } diff --git a/libsecondlife-cs/examples/IA_NotecardTool/NotecardTool.cs b/libsecondlife-cs/examples/IA_NotecardTool/NotecardTool.cs index e8424bac..5f6b98ca 100644 --- a/libsecondlife-cs/examples/IA_NotecardTool/NotecardTool.cs +++ b/libsecondlife-cs/examples/IA_NotecardTool/NotecardTool.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading; using IA_SimpleInventory; using libsecondlife; @@ -35,12 +36,16 @@ using libsecondlife.InventorySystem; namespace IA_NotecardTool { - class NotecardTool : SimpleInventory + class NotecardTool { private string FileName; private string NotecardName; - static new void Main(string[] args) + private SecondLife _Client; + private ManualResetEvent ConnectedSignal = new ManualResetEvent(false); + + + static void Main(string[] args) { if (args.Length < 6) { @@ -59,21 +64,22 @@ namespace IA_NotecardTool tool.FileName = args[5]; tool.Connect(args[0], args[1], args[2]); - tool.doStuff(); - tool.Disconnect(); - - System.Threading.Thread.Sleep(500); + if (tool.ConnectedSignal.WaitOne(TimeSpan.FromMinutes(1), false)) + { + tool.doStuff(); + tool.Disconnect(); + } } - private new void doStuff() + private void doStuff() { Console.WriteLine("Reading " + FileName); StreamReader sr = File.OpenText(FileName); string Body = sr.ReadToEnd(); Console.WriteLine("Getting Notecard Folder"); - InventoryFolder iFolder = base.AgentInventory.getFolder("Notecards"); + InventoryFolder iFolder = _Client.Inventory.getFolder("Notecards"); Console.WriteLine("Creating Notecard"); @@ -81,5 +87,55 @@ namespace IA_NotecardTool Console.WriteLine("Done."); } + + public NotecardTool() + { + try + { + _Client = new SecondLife(); + _Client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); + } + catch (Exception e) + { + // Error initializing the client + Console.WriteLine(); + Console.WriteLine(e.ToString()); + } + } + + void Network_OnConnected(object sender) + { + ConnectedSignal.Set(); + } + + protected bool Connect(string FirstName, string LastName, string Password) + { + Console.WriteLine("Attempting to connect and login to SecondLife."); + + // Setup Login to Second Life + Dictionary loginReply = new Dictionary(); + + // Login + if (!_Client.Network.Login(FirstName, LastName, Password, "createnotecard", "static.sprocket@gmail.com")) + { + // Login failed + Console.WriteLine("Error logging in: " + _Client.Network.LoginError); + return false; + } + + // Login was successful + Console.WriteLine("Login was successful."); + Console.WriteLine("AgentID: " + _Client.Network.AgentID); + Console.WriteLine("SessionID: " + _Client.Network.SessionID); + + return true; + } + + protected void Disconnect() + { + // Logout of Second Life + Console.WriteLine("Request logout"); + _Client.Network.Logout(); + } } } diff --git a/libsecondlife-cs/examples/IA_SimpleInventory/IA_SimpleInventory.cs b/libsecondlife-cs/examples/IA_SimpleInventory/IA_SimpleInventory.cs index 17507425..b25ab693 100644 --- a/libsecondlife-cs/examples/IA_SimpleInventory/IA_SimpleInventory.cs +++ b/libsecondlife-cs/examples/IA_SimpleInventory/IA_SimpleInventory.cs @@ -27,6 +27,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Threading; using libsecondlife; using libsecondlife.InventorySystem; @@ -38,10 +39,8 @@ namespace IA_SimpleInventory /// public class SimpleInventory { - protected SecondLife client; - protected InventoryManager AgentInventory; - - protected bool DownloadInventoryOnConnect = true; + private SecondLife client; + private ManualResetEvent ConnectedSignal = new ManualResetEvent(false); public static void Main(string[] args) { @@ -53,9 +52,14 @@ namespace IA_SimpleInventory } SimpleInventory simple = new SimpleInventory(); - simple.Connect(args[0], args[1], args[2]); - simple.doStuff(); - simple.Disconnect(); + if (simple.Connect(args[0], args[1], args[2])) + { + if (simple.ConnectedSignal.WaitOne(TimeSpan.FromMinutes(1), false)) + { + simple.doStuff(); + simple.Disconnect(); + } + } } protected SimpleInventory() @@ -63,6 +67,7 @@ namespace IA_SimpleInventory try { client = new SecondLife(); + client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); } catch (Exception e) { @@ -72,6 +77,11 @@ namespace IA_SimpleInventory } } + void Network_OnConnected(object sender) + { + ConnectedSignal.Set(); + } + protected bool Connect(string FirstName, string LastName, string Password) { Console.WriteLine("Attempting to connect and login to SecondLife."); @@ -80,7 +90,7 @@ namespace IA_SimpleInventory Dictionary loginReply = new Dictionary(); // Login - if (!client.Network.Login(FirstName, LastName, Password, "createnotecard", "static.sprocket@gmail.com")) + if (!client.Network.Login(FirstName, LastName, Password, "IA_SimpleInventory", "static.sprocket@gmail.com")) { // Login failed Console.WriteLine("Error logging in: " + client.Network.LoginError); @@ -92,22 +102,6 @@ namespace IA_SimpleInventory Console.WriteLine("AgentID: " + client.Network.AgentID); Console.WriteLine("SessionID: " + client.Network.SessionID); - // Get Root Inventory Folder UUID - Console.WriteLine("Pulling root folder UUID from login data."); - ArrayList alInventoryRoot = (ArrayList)client.Network.LoginValues["inventory-root"]; - Hashtable htInventoryRoot = (Hashtable)alInventoryRoot[0]; - LLUUID agentRootFolderID = new LLUUID((string)htInventoryRoot["folder_id"]); - - // Initialize Inventory Manager object - Console.WriteLine("Initializing Inventory Manager."); - AgentInventory = new InventoryManager(client, agentRootFolderID); - - if (DownloadInventoryOnConnect) - { - // and request an inventory download - Console.WriteLine("Downloading Inventory."); - AgentInventory.DownloadInventory(); - } return true; } @@ -120,17 +114,19 @@ namespace IA_SimpleInventory protected void doStuff() { + // and request an inventory download + Console.WriteLine("Downloading Inventory."); + client.Inventory.DownloadInventory(); + + Console.WriteLine("Dumping a copy of " + client.Self.FirstName + "'s inventory to the console."); Console.WriteLine(); - if (AgentInventory != null) - { - InventoryFolder root = AgentInventory.getRootFolder(); + InventoryFolder root = client.Inventory.getRootFolder(); - if (root != null) - { - Console.WriteLine(root.toXML(false)); - } + if (root != null) + { + Console.WriteLine(root.toXML(false)); } } } diff --git a/libsecondlife-cs/examples/IA_TestAsyncImage/IA_TestAsyncImage.cs b/libsecondlife-cs/examples/IA_TestAsyncImage/IA_TestAsyncImage.cs index 0d7a6e61..1d32e162 100644 --- a/libsecondlife-cs/examples/IA_TestAsyncImage/IA_TestAsyncImage.cs +++ b/libsecondlife-cs/examples/IA_TestAsyncImage/IA_TestAsyncImage.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; + using IA_SimpleInventory; using libsecondlife; @@ -10,76 +11,79 @@ using libsecondlife.AssetSystem; namespace IA_TestAsyncImage { - class TestAsync : SimpleInventory + class TestAsync { - ImageManager imgManager; + private SecondLife _Client; + private ManualResetEvent ConnectedSignal = new ManualResetEvent(false); - Queue TextureQueue = new Queue(); - string OutputDirectory = "IA_TestAsyncImages"; + private Queue TextureQueue = new Queue(); + + private string OutputDirectory = "IA_TestAsyncImages"; [STAThread] - static new void Main(string[] args) + static void Main(string[] args) { TestAsync app = new TestAsync(); - app.DownloadInventoryOnConnect = false; - app.client.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(app.Objects_OnNewPrim); - app.client.Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(app.Objects_OnNewAvatar); + app._Client.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(app.Objects_OnNewPrim); + app._Client.Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(app.Objects_OnNewAvatar); app.Connect(args[0], args[1], args[2]); - app.doStuff(); - app.Disconnect(); - - System.Threading.Thread.Sleep(500); - + if (app.ConnectedSignal.WaitOne(TimeSpan.FromMinutes(1), false)) + { + app.doStuff(); + app.Disconnect(); + } Console.WriteLine("Done..."); } + public TestAsync() + { + try + { + _Client = new SecondLife(); + _Client.Images = new ImageManager(_Client, ImageManager.CacheTypes.Disk, OutputDirectory); + _Client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected); + } + catch (Exception e) + { + // Error initializing the client + Console.WriteLine(); + Console.WriteLine(e.ToString()); + } + } + private void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation) { - if (imgManager == null) + if (avatar.FirstLifeImage != null) { - Console.WriteLine("ImageManager not ready yet, queueing Avatar textures."); - TextureQueue.Enqueue(avatar.FirstLifeImage); - TextureQueue.Enqueue(avatar.ProfileImage); - - foreach (TextureEntryFace tef in avatar.Textures.FaceTextures.Values) + if (_Client.Images.isCachedImage(avatar.FirstLifeImage) == false) { - TextureQueue.Enqueue(tef.TextureID); + _Client.Images.RequestImageAsync(avatar.FirstLifeImage); } } - else + + if (avatar.ProfileImage != null) { - if (avatar.FirstLifeImage != null) + if (_Client.Images.isCachedImage(avatar.FirstLifeImage) == false) { - if (imgManager.isCachedImage(avatar.FirstLifeImage) == false) - { - imgManager.RequestImageAsync(avatar.FirstLifeImage); - } + _Client.Images.RequestImageAsync(avatar.ProfileImage); } + } - if (avatar.ProfileImage != null) + if (avatar.Textures != null) + { + foreach (TextureEntryFace tef in avatar.Textures.FaceTextures.Values) { - if (imgManager.isCachedImage(avatar.FirstLifeImage) == false) + if (_Client.Images.isCachedImage(tef.TextureID) == false) { - imgManager.RequestImageAsync(avatar.ProfileImage); + _Client.Images.RequestImageAsync(tef.TextureID); } - } - - if (avatar.Textures != null) - { - foreach (TextureEntryFace tef in avatar.Textures.FaceTextures.Values) + else { - if (imgManager.isCachedImage(tef.TextureID) == false) - { - imgManager.RequestImageAsync(tef.TextureID); - } - else - { - Console.WriteLine("Already cached: " + tef.TextureID); - } + Console.WriteLine("Already cached: " + tef.TextureID); } } } @@ -87,42 +91,29 @@ namespace IA_TestAsyncImage private void Objects_OnNewPrim(Simulator simulator, PrimObject prim, ulong regionHandle, ushort timeDilation) { - if (imgManager == null) + if ((prim.Textures.DefaultTexture != null) && (prim.Textures.DefaultTexture.TextureID != null)) { - Console.WriteLine("ImageManager not ready yet, queueing Prim textures."); - TextureQueue.Enqueue(prim.Textures.DefaultTexture.TextureID); - - foreach (TextureEntryFace tef in prim.Textures.FaceTextures.Values) + if (_Client.Images.isCachedImage(prim.Textures.DefaultTexture.TextureID) == false) { - TextureQueue.Enqueue(tef.TextureID); + _Client.Images.RequestImageAsync(prim.Textures.DefaultTexture.TextureID); + } + else + { + Console.WriteLine("Already cached: " + prim.Textures.DefaultTexture.TextureID); } } - else + + if (prim.Textures.FaceTextures != null) { - if ((prim.Textures.DefaultTexture != null) && (prim.Textures.DefaultTexture.TextureID != null)) + foreach (TextureEntryFace tef in prim.Textures.FaceTextures.Values) { - if (imgManager.isCachedImage(prim.Textures.DefaultTexture.TextureID) == false) + if (_Client.Images.isCachedImage(tef.TextureID) == false) { - imgManager.RequestImageAsync(prim.Textures.DefaultTexture.TextureID); + _Client.Images.RequestImageAsync(tef.TextureID); } else { - Console.WriteLine("Already cached: " + prim.Textures.DefaultTexture.TextureID); - } - } - - if (prim.Textures.FaceTextures != null) - { - foreach (TextureEntryFace tef in prim.Textures.FaceTextures.Values) - { - if (imgManager.isCachedImage(tef.TextureID) == false) - { - imgManager.RequestImageAsync(tef.TextureID); - } - else - { - Console.WriteLine("Already cached: " + tef.TextureID); - } + Console.WriteLine("Already cached: " + tef.TextureID); } } } @@ -153,14 +144,14 @@ namespace IA_TestAsyncImage } } - protected new void doStuff() + protected void doStuff() { - imgManager = new ImageManager(client, ImageManager.CacheTypes.Disk, OutputDirectory); - imgManager.OnImageRetrieved += new ImageRetrievedCallback(NewImageRetrievedCallBack); + + _Client.Images.OnImageRetrieved += new ImageRetrievedCallback(NewImageRetrievedCallBack); while (TextureQueue.Count > 0) { - imgManager.RequestImageAsync(TextureQueue.Dequeue()); + _Client.Images.RequestImageAsync(TextureQueue.Dequeue()); } Console.WriteLine("Press any key to stop."); @@ -183,5 +174,40 @@ namespace IA_TestAsyncImage File.WriteAllBytes(filename, JasperWrapper.jasper_decode_j2c_to_tiff(j2cdata)); } } + + void Network_OnConnected(object sender) + { + ConnectedSignal.Set(); + } + + protected bool Connect(string FirstName, string LastName, string Password) + { + Console.WriteLine("Attempting to connect and login to SecondLife."); + + // Setup Login to Second Life + Dictionary loginReply = new Dictionary(); + + // Login + if (!_Client.Network.Login(FirstName, LastName, Password, "createnotecard", "static.sprocket@gmail.com")) + { + // Login failed + Console.WriteLine("Error logging in: " + _Client.Network.LoginError); + return false; + } + + // Login was successful + Console.WriteLine("Login was successful."); + Console.WriteLine("AgentID: " + _Client.Network.AgentID); + Console.WriteLine("SessionID: " + _Client.Network.SessionID); + + return true; + } + + protected void Disconnect() + { + // Logout of Second Life + Console.WriteLine("Request logout"); + _Client.Network.Logout(); + } } } diff --git a/libsecondlife-cs/examples/Teleport/Teleport.cs b/libsecondlife-cs/examples/Teleport/Teleport.cs index 6cc49088..2fa19810 100644 --- a/libsecondlife-cs/examples/Teleport/Teleport.cs +++ b/libsecondlife-cs/examples/Teleport/Teleport.cs @@ -136,7 +136,7 @@ namespace Teleport } } - Client.Self.OnTeleport += new TeleportCallback(Avatar_OnTeleportMessage); + Client.Self.OnTeleport += new TeleportCallback(Self_OnTeleport); DoneTeleporting = false; Client.Self.Teleport(RegionHandle, coords); @@ -147,7 +147,7 @@ namespace Teleport } } - private void Avatar_OnTeleportMessage(Simulator currentSim, string message, TeleportStatus status) + void Self_OnTeleport(Simulator currentSim, string message, TeleportStatus status) { Console.WriteLine(message); diff --git a/libsecondlife-cs/libsecondlife.csproj b/libsecondlife-cs/libsecondlife.csproj index 1209e33c..3d99dcc5 100644 --- a/libsecondlife-cs/libsecondlife.csproj +++ b/libsecondlife-cs/libsecondlife.csproj @@ -107,6 +107,8 @@ Code + +