OSDN Git Service

Adjust to the introduction of FolderType ENUM in libomv
[radegast/radegast.git] / Radegast / GUI / Consoles / Inventory / CurrentOutfitFolder.cs
index 752513d..78602f8 100644 (file)
@@ -1,6 +1,6 @@
 // 
 // Radegast Metaverse Client
-// Copyright (c) 2009-2012, Radegast Development Team
+// Copyright (c) 2009-2014, Radegast Development Team
 // All rights reserved.
 // 
 // Redistribution and use in source and binary forms, with or without
@@ -44,13 +44,12 @@ namespace Radegast
         GridClient Client;
         RadegastInstance Instance;
         bool InitiCOF = false;
-        bool InvCAP = false;
         bool AppearanceSent = false;
         bool COFReady = false;
         bool InitialUpdateDone = false;
-        public List<InventoryItem> ContentLinks = new List<InventoryItem>();
         public Dictionary<UUID, InventoryItem> Content = new Dictionary<UUID, InventoryItem>();
         public InventoryFolder COF;
+
         #endregion Fields
 
         #region Construction and disposal
@@ -94,9 +93,7 @@ namespace Radegast
             client.Appearance.AppearanceSet -= new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
             client.Objects.KillObject -= new EventHandler<KillObjectEventArgs>(Objects_KillObject);
             lock (Content) Content.Clear();
-            lock (ContentLinks) ContentLinks.Clear();
             InitiCOF = false;
-            InvCAP = false;
             AppearanceSent = false;
             COFReady = false;
             InitialUpdateDone = false;
@@ -113,34 +110,45 @@ namespace Radegast
 
         void Inventory_ItemReceived(object sender, ItemReceivedEventArgs e)
         {
-            lock (ContentLinks)
+            bool partOfCOF = false;
+            var links = ContentLinks();
+            foreach (var cofItem in links)
             {
-                bool partOfCOF = false;
-                foreach (var cofItem in ContentLinks)
+                if (cofItem.AssetUUID == e.Item.UUID)
                 {
-                    if (cofItem.AssetUUID == e.Item.UUID)
-                    {
-                        partOfCOF = true;
-                        break;
-                    }
+                    partOfCOF = true;
+                    break;
                 }
+            }
 
-                if (partOfCOF)
+            if (partOfCOF)
+            {
+                lock (Content)
                 {
-                    lock (Content)
-                    {
-                        Content[e.Item.UUID] = e.Item;
-                    }
+                    Content[e.Item.UUID] = e.Item;
                 }
             }
 
-            if (Content.Count == ContentLinks.Count)
+            if (Content.Count == links.Count)
             {
                 COFReady = true;
                 if (AppearanceSent)
                 {
                     InitialUpdate();
                 }
+                lock (Content)
+                {
+                    foreach (InventoryItem link in Content.Values)
+                    {
+                        if (link.InventoryType == InventoryType.Wearable)
+                        {
+                            InventoryWearable w = (InventoryWearable)link;
+                            InventoryItem lk = links.Find(l => l.AssetUUID == w.UUID);
+                            // Logger.DebugLog(string.Format("\nName: {0}\nDescription: {1}\nType: {2} - {3}", w.Name, lk == null ? "" : lk.Description, w.Flags.ToString(), w.WearableType.ToString())); ;
+                        }
+                    }
+
+                }
             }
         }
 
@@ -152,34 +160,23 @@ namespace Radegast
 
             if (e.FolderID == COF.UUID && e.Success)
             {
+                COF = (InventoryFolder)Client.Inventory.Store[COF.UUID];
                 lock (FolderSync)
                 {
                     lock (Content) Content.Clear();
-                    lock (ContentLinks) ContentLinks.Clear();
 
-                    List<InventoryBase> content = Client.Inventory.Store.GetContents(COF);
-                    foreach (var baseItem in content)
-                    {
-                        if (baseItem is InventoryItem)
-                        {
-                            InventoryItem item = (InventoryItem)baseItem;
-                            if (item.AssetType == AssetType.Link)
-                            {
-                                ContentLinks.Add(item);
-                            }
-                        }
-                    }
 
                     List<UUID> items = new List<UUID>();
                     List<UUID> owners = new List<UUID>();
 
-                    lock (ContentLinks)
+                    foreach (var link in ContentLinks())
                     {
-                        foreach (var link in ContentLinks)
-                        {
-                            items.Add(link.AssetUUID);
-                            owners.Add(Client.Self.AgentID);
-                        }
+                        //if (Client.Inventory.Store.Contains(link.AssetUUID))
+                        //{
+                        //    continue;
+                        //}
+                        items.Add(link.AssetUUID);
+                        owners.Add(Client.Self.AgentID);
                     }
 
                     if (items.Count > 0)
@@ -218,34 +215,15 @@ namespace Radegast
         #region Private methods
         void RequestDescendants(UUID folderID)
         {
-            if (InvCAP)
-            {
-                Client.Inventory.RequestFolderContentsCap(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
-            }
-            else
-            {
-                Client.Inventory.RequestFolderContents(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
-            }
+            Client.Inventory.RequestFolderContents(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
         }
 
         void InitCOF()
         {
-            Uri url = null;
-
-            if (Client.Network.CurrentSim.Caps == null ||
-                null == (url = Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventoryDescendents2")))
-            {
-                InvCAP = false;
-            }
-            else
-            {
-                InvCAP = true;
-            }
-
             List<InventoryBase> rootContent = Client.Inventory.Store.GetContents(Client.Inventory.Store.RootFolder.UUID);
             foreach (InventoryBase baseItem in rootContent)
             {
-                if (baseItem is InventoryFolder && ((InventoryFolder)baseItem).PreferredType == AssetType.CurrentOutfitFolder)
+                if (baseItem is InventoryFolder && ((InventoryFolder)baseItem).PreferredType == FolderType.CurrentOutfit)
                 {
                     COF = (InventoryFolder)baseItem;
                     break;
@@ -264,7 +242,7 @@ namespace Radegast
 
         void CreateCOF()
         {
-            UUID cofID = Client.Inventory.CreateFolder(Client.Inventory.Store.RootFolder.UUID, "Current Look", AssetType.CurrentOutfitFolder);
+            UUID cofID = Client.Inventory.CreateFolder(Client.Inventory.Store.RootFolder.UUID, "Current Look", FolderType.CurrentOutfit);
             if (Client.Inventory.Store.Items.ContainsKey(cofID) && Client.Inventory.Store.Items[cofID].Data is InventoryFolder)
             {
                 COF = (InventoryFolder)Client.Inventory.Store.Items[cofID].Data;
@@ -300,6 +278,22 @@ namespace Radegast
 
         #region Public methods
         /// <summary>
+        /// Get COF contents
+        /// </summary>
+        /// <returns>List if InventoryItems that can be part of appearance (attachments, wearables)</returns>
+        public List<InventoryItem> ContentLinks()
+        {
+            List<InventoryItem> ret = new List<InventoryItem>();
+            if (COF == null) return ret;
+
+            Client.Inventory.Store.GetContents(COF)
+                .FindAll(b => CanBeWorn(b) && ((InventoryItem)b).AssetType == AssetType.Link)
+                .ForEach(item => ret.Add((InventoryItem)item));
+
+            return ret;
+        }
+
+        /// <summary>
         /// Get inventory ID of a prim
         /// </summary>
         /// <param name="prim">Prim to check</param>
@@ -338,6 +332,34 @@ namespace Radegast
         }
 
         /// <summary>
+        /// Checks if inventory item of Wearable type is worn
+        /// </summary>
+        /// <param name="currentlyWorn">Current outfit</param>
+        /// <param name="item">Item to check</param>
+        /// <returns>True if the item is worn</returns>
+        public static bool IsWorn(Dictionary<WearableType, AppearanceManager.WearableData> currentlyWorn, InventoryItem item)
+        {
+            foreach (var n in currentlyWorn.Values)
+            {
+                if (n.ItemID == item.UUID)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Can this inventory type be worn
+        /// </summary>
+        /// <param name="item">Item to check</param>
+        /// <returns>True if the inventory item can be worn</returns>
+        public static bool CanBeWorn(InventoryBase item)
+        {
+            return item is InventoryWearable || item is InventoryAttachment || item is InventoryObject;
+        }
+
+        /// <summary>
         /// Attach an inventory item
         /// </summary>
         /// <param name="item">Item to be attached</param>
@@ -346,23 +368,48 @@ namespace Radegast
         public void Attach(InventoryItem item, AttachmentPoint point, bool replace)
         {
             Client.Appearance.Attach(item, point, replace);
-            if (COF == null) return;
+            AddLink(item);
+        }
 
-            bool linkExists = false;
-            lock (ContentLinks)
+        /// <summary>
+        /// Creates a new COF link
+        /// </summary>
+        /// <param name="item">Original item to be linked from COF</param>
+        public void AddLink(InventoryItem item)
+        {
+            if (item.InventoryType == InventoryType.Wearable && !IsBodyPart(item))
+            {
+                InventoryWearable w = (InventoryWearable)item;
+                int layer = 0;
+                string desc = string.Format("@{0}{1:00}", (int)w.WearableType, layer);
+                AddLink(item, desc);
+            }
+            else
             {
-                linkExists = null != ContentLinks.Find(itemLink => itemLink.AssetUUID == item.UUID);
+                AddLink(item, string.Empty);
             }
+        }
+
+        /// <summary>
+        /// Creates a new COF link
+        /// </summary>
+        /// <param name="item">Original item to be linked from COF</param>
+        /// <param name="newDescription">Description for the link</param>
+        public void AddLink(InventoryItem item, string newDescription)
+        {
+            if (COF == null) return;
+
+            bool linkExists = false;
+
+            linkExists = null != ContentLinks().Find(itemLink => itemLink.AssetUUID == item.UUID);
+
             if (!linkExists)
             {
-                Client.Inventory.CreateLink(COF.UUID, item, (success, newItem) =>
+                Client.Inventory.CreateLink(COF.UUID, item.UUID, item.Name, newDescription, AssetType.Link, item.InventoryType, UUID.Random(), (success, newItem) =>
                 {
                     if (success)
                     {
-                        lock (ContentLinks)
-                        {
-                            ContentLinks.Add(newItem);
-                        }
+                        Client.Inventory.RequestFetchInventory(newItem.UUID, newItem.OwnerID);
                     }
                 });
             }
@@ -374,17 +421,26 @@ namespace Radegast
         /// <param name="itemID">ID of the target inventory item for which we want link to be removed</param>
         public void RemoveLink(UUID itemID)
         {
+            RemoveLink(new List<UUID>(1) { itemID });
+        }
+
+        /// <summary>
+        /// Remove a link to specified inventory item
+        /// </summary>
+        /// <param name="itemIDs">List of IDs of the target inventory item for which we want link to be removed</param>
+        public void RemoveLink(List<UUID> itemIDs)
+        {
             if (COF == null) return;
 
-            lock (ContentLinks)
+            List<UUID> toRemove = new List<UUID>();
+
+            foreach (UUID itemID in itemIDs)
             {
-                InventoryItem attachment = ContentLinks.Find(itemLink => itemLink.AssetUUID == itemID);
-                if (attachment != null)
-                {
-                    Client.Inventory.RemoveItem(attachment.UUID);
-                    ContentLinks.Remove(attachment);
-                }
+                var links = ContentLinks().FindAll(itemLink => itemLink.AssetUUID == itemID);
+                links.ForEach(item => toRemove.Add(item.UUID));
             }
+
+            Client.Inventory.Remove(toRemove, null);
         }
 
         /// <summary>
@@ -396,6 +452,233 @@ namespace Radegast
             Client.Appearance.Detach(item);
             RemoveLink(item.UUID);
         }
+
+        public List<InventoryItem> GetWornAt(WearableType type)
+        {
+            var ret = new List<InventoryItem>();
+            ContentLinks().ForEach(link =>
+            {
+                var item = RealInventoryItem(link);
+                if (item is InventoryWearable)
+                {
+                    var w = (InventoryWearable)item;
+                    if (w.WearableType == type)
+                    {
+                        ret.Add(item);
+                    }
+                }
+            });
+
+            return ret;
+        }
+
+        /// <summary>
+        /// Resolves inventory links and returns a real inventory item that
+        /// the link is pointing to
+        /// </summary>
+        /// <param name="item"></param>
+        /// <returns></returns>
+        public InventoryItem RealInventoryItem(InventoryItem item)
+        {
+            if (item.IsLink() && Client.Inventory.Store.Contains(item.AssetUUID) && Client.Inventory.Store[item.AssetUUID] is InventoryItem)
+            {
+                return (InventoryItem)Client.Inventory.Store[item.AssetUUID];
+            }
+
+            return item;
+        }
+
+        /// <summary>
+        /// Replaces the current outfit and updates COF links accordingly
+        /// </summary>
+        /// <param name="outfit">List of new wearables and attachments that comprise the new outfit</param>
+        public void ReplaceOutfit(List<InventoryItem> newOutfit)
+        {
+            // Resolve inventory links
+            List<InventoryItem> outfit = new List<InventoryItem>();
+            foreach (var item in newOutfit)
+            {
+                outfit.Add(RealInventoryItem(item));
+            }
+
+            // Remove links to all exiting items
+            List<UUID> toRemove = new List<UUID>();
+            ContentLinks().ForEach(item =>
+            {
+                if (IsBodyPart(item))
+                {
+                    WearableType linkType = ((InventoryWearable)RealInventoryItem(item)).WearableType;
+                    bool hasBodyPart = false;
+
+                    foreach (var newItemTmp in newOutfit)
+                    {
+                        var newItem = RealInventoryItem(newItemTmp);
+                        if (IsBodyPart(newItem))
+                        {
+                            if (((InventoryWearable)newItem).WearableType == linkType)
+                            {
+                                hasBodyPart = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (hasBodyPart)
+                    {
+                        toRemove.Add(item.UUID);
+                    }
+                }
+                else
+                {
+                    toRemove.Add(item.UUID);
+                }
+            });
+
+            Client.Inventory.Remove(toRemove, null);
+
+            // Add links to new items
+            List<InventoryItem> newItems = outfit.FindAll(item => CanBeWorn(item));
+            foreach (var item in newItems)
+            {
+                AddLink(item);
+            }
+
+            Client.Appearance.ReplaceOutfit(outfit, false);
+            WorkPool.QueueUserWorkItem(sync =>
+            {
+                Thread.Sleep(2000);
+                Client.Appearance.RequestSetAppearance(true);
+            });
+        }
+
+        /// <summary>
+        /// Add items to current outfit
+        /// </summary>
+        /// <param name="item">Item to add</param>
+        /// <param name="replace">Should existing wearable of the same type be removed</param>
+        public void AddToOutfit(InventoryItem item, bool replace)
+        {
+            AddToOutfit(new List<InventoryItem>(1) { item }, replace);
+        }
+
+        /// <summary>
+        /// Add items to current outfit
+        /// </summary>
+        /// <param name="items">List of items to add</param>
+        /// <param name="replace">Should existing wearable of the same type be removed</param>
+        public void AddToOutfit(List<InventoryItem> items, bool replace)
+        {
+            List<InventoryItem> current = ContentLinks();
+            List<UUID> toRemove = new List<UUID>();
+
+            // Resolve inventory links and remove wearables of the same type from COF
+            List<InventoryItem> outfit = new List<InventoryItem>();
+
+            foreach (var item in items)
+            {
+                InventoryItem realItem = RealInventoryItem(item);
+                if (realItem is InventoryWearable)
+                {
+                    foreach (var link in current)
+                    {
+                        var currentItem = RealInventoryItem(link);
+                        if (link.AssetUUID == item.UUID)
+                        {
+                            toRemove.Add(link.UUID);
+                        }
+                        else if (currentItem is InventoryWearable)
+                        {
+                            var w = (InventoryWearable)currentItem;
+                            if (w.WearableType == ((InventoryWearable)realItem).WearableType)
+                            {
+                                toRemove.Add(link.UUID);
+                            }
+                        }
+                    }
+                }
+
+                outfit.Add(realItem);
+            }
+            Client.Inventory.Remove(toRemove, null);
+
+            // Add links to new items
+            List<InventoryItem> newItems = outfit.FindAll(item => CanBeWorn(item));
+            foreach (var item in newItems)
+            {
+                AddLink(item);
+            }
+
+            Client.Appearance.AddToOutfit(outfit, replace);
+            WorkPool.QueueUserWorkItem(sync =>
+            {
+                Thread.Sleep(2000);
+                Client.Appearance.RequestSetAppearance(true);
+            });
+        }
+
+        /// <summary>
+        /// Remove an item from the current outfit
+        /// </summary>
+        /// <param name="items">Item to remove</param>
+        public void RemoveFromOutfit(InventoryItem item)
+        {
+            RemoveFromOutfit(new List<InventoryItem>(1) { item });
+        }
+
+        /// <summary>
+        /// Remove specified items from the current outfit
+        /// </summary>
+        /// <param name="items">List of items to remove</param>
+        public void RemoveFromOutfit(List<InventoryItem> items)
+        {
+            // Resolve inventory links
+            List<InventoryItem> outfit = new List<InventoryItem>();
+            foreach (var item in items)
+            {
+                var realItem = RealInventoryItem(item);
+                if (Instance.RLV.AllowDetach(realItem))
+                {
+                    outfit.Add(realItem);
+                }
+            }
+
+            // Remove links to all items that were removed
+            List<UUID> toRemove = new List<UUID>();
+            foreach (InventoryItem item in outfit.FindAll(item => CanBeWorn(item) && !IsBodyPart(item)))
+            {
+                toRemove.Add(item.UUID);
+            }
+            RemoveLink(toRemove);
+
+            Client.Appearance.RemoveFromOutfit(outfit);
+        }
+
+        public bool IsBodyPart(InventoryItem item)
+        {
+            var realItem = RealInventoryItem(item);
+            if (realItem is InventoryWearable)
+            {
+                var w = (InventoryWearable)realItem;
+                var t = w.WearableType;
+                if (t == WearableType.Shape ||
+                    t == WearableType.Skin ||
+                    t == WearableType.Eyes ||
+                    t == WearableType.Hair)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Force rebaking textures
+        /// </summary>
+        public void RebakeTextures()
+        {
+            Client.Appearance.RequestSetAppearance(true);
+        }
+
         #endregion Public methods
     }
 }