//
// 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
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
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;
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())); ;
+ }
+ }
+
+ }
}
}
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)
#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;
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;
#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>
}
/// <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>
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);
}
});
}
/// <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>
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
}
}