2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2012, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 using System.Collections;
33 using System.Collections.Generic;
35 using System.Threading;
37 using OpenMetaverse.StructuredData;
41 public class CurrentOutfitFolder : IDisposable
45 RadegastInstance Instance;
46 bool InitiCOF = false;
48 bool AppearanceSent = false;
49 bool COFReady = false;
50 bool InitialUpdateDone = false;
51 public List<InventoryItem> ContentLinks = new List<InventoryItem>();
52 public Dictionary<UUID, InventoryItem> Content = new Dictionary<UUID, InventoryItem>();
53 public InventoryFolder COF;
56 #region Construction and disposal
57 public CurrentOutfitFolder(RadegastInstance instance)
59 this.Instance = instance;
60 this.Client = instance.Client;
61 Instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
62 RegisterClientEvents(Client);
67 UnregisterClientEvents(Client);
68 Instance.ClientChanged -= new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
70 #endregion Construction and disposal
72 #region Event handling
73 void instance_ClientChanged(object sender, ClientChangedEventArgs e)
75 UnregisterClientEvents(Client);
77 RegisterClientEvents(Client);
80 void RegisterClientEvents(GridClient client)
82 client.Network.EventQueueRunning += new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
83 client.Inventory.FolderUpdated += new EventHandler<FolderUpdatedEventArgs>(Inventory_FolderUpdated);
84 client.Inventory.ItemReceived += new EventHandler<ItemReceivedEventArgs>(Inventory_ItemReceived);
85 client.Appearance.AppearanceSet += new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
86 client.Objects.KillObject += new EventHandler<KillObjectEventArgs>(Objects_KillObject);
89 void UnregisterClientEvents(GridClient client)
91 client.Network.EventQueueRunning -= new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
92 client.Inventory.FolderUpdated -= new EventHandler<FolderUpdatedEventArgs>(Inventory_FolderUpdated);
93 client.Inventory.ItemReceived -= new EventHandler<ItemReceivedEventArgs>(Inventory_ItemReceived);
94 client.Appearance.AppearanceSet -= new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
95 client.Objects.KillObject -= new EventHandler<KillObjectEventArgs>(Objects_KillObject);
96 lock (Content) Content.Clear();
97 lock (ContentLinks) ContentLinks.Clear();
100 AppearanceSent = false;
102 InitialUpdateDone = false;
105 void Appearance_AppearanceSet(object sender, AppearanceSetEventArgs e)
107 AppearanceSent = true;
114 void Inventory_ItemReceived(object sender, ItemReceivedEventArgs e)
118 bool partOfCOF = false;
119 foreach (var cofItem in ContentLinks)
121 if (cofItem.AssetUUID == e.Item.UUID)
132 Content[e.Item.UUID] = e.Item;
137 if (Content.Count == ContentLinks.Count)
147 object FolderSync = new object();
149 void Inventory_FolderUpdated(object sender, FolderUpdatedEventArgs e)
151 if (COF == null) return;
153 if (e.FolderID == COF.UUID && e.Success)
157 lock (Content) Content.Clear();
158 lock (ContentLinks) ContentLinks.Clear();
160 List<InventoryBase> content = Client.Inventory.Store.GetContents(COF);
161 foreach (var baseItem in content)
163 if (baseItem is InventoryItem)
165 InventoryItem item = (InventoryItem)baseItem;
166 if (item.AssetType == AssetType.Link)
168 ContentLinks.Add(item);
173 List<UUID> items = new List<UUID>();
174 List<UUID> owners = new List<UUID>();
178 foreach (var link in ContentLinks)
180 items.Add(link.AssetUUID);
181 owners.Add(Client.Self.AgentID);
187 Client.Inventory.RequestFetchInventory(items, owners);
193 void Objects_KillObject(object sender, KillObjectEventArgs e)
195 if (Client.Network.CurrentSim != e.Simulator) return;
197 Primitive prim = null;
198 if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(e.ObjectLocalID, out prim))
200 UUID invItem = GetAttachmentItem(prim);
201 if (invItem != UUID.Zero)
208 void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e)
210 if (e.Simulator == Client.Network.CurrentSim && !InitiCOF)
216 #endregion Event handling
218 #region Private methods
219 void RequestDescendants(UUID folderID)
223 Client.Inventory.RequestFolderContentsCap(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
227 Client.Inventory.RequestFolderContents(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
235 if (Client.Network.CurrentSim.Caps == null ||
236 null == (url = Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventoryDescendents2")))
245 List<InventoryBase> rootContent = Client.Inventory.Store.GetContents(Client.Inventory.Store.RootFolder.UUID);
246 foreach (InventoryBase baseItem in rootContent)
248 if (baseItem is InventoryFolder && ((InventoryFolder)baseItem).PreferredType == AssetType.CurrentOutfitFolder)
250 COF = (InventoryFolder)baseItem;
261 RequestDescendants(COF.UUID);
267 UUID cofID = Client.Inventory.CreateFolder(Client.Inventory.Store.RootFolder.UUID, "Current Look", AssetType.CurrentOutfitFolder);
268 if (Client.Inventory.Store.Items.ContainsKey(cofID) && Client.Inventory.Store.Items[cofID].Data is InventoryFolder)
270 COF = (InventoryFolder)Client.Inventory.Store.Items[cofID].Data;
281 if (InitialUpdateDone) return;
282 InitialUpdateDone = true;
285 List<Primitive> myAtt = Client.Network.CurrentSim.ObjectsPrimitives.FindAll((Primitive p) => p.ParentID == Client.Self.LocalID);
287 foreach (InventoryItem item in Content.Values)
289 if (item is InventoryObject || item is InventoryAttachment)
291 if (!IsAttached(myAtt, item))
293 Client.Appearance.Attach(item, AttachmentPoint.Default, false);
299 #endregion Private methods
301 #region Public methods
303 /// Get inventory ID of a prim
305 /// <param name="prim">Prim to check</param>
306 /// <returns>Inventory ID of the object. UUID.Zero if not found</returns>
307 public static UUID GetAttachmentItem(Primitive prim)
309 if (prim.NameValues == null) return UUID.Zero;
311 for (int i = 0; i < prim.NameValues.Length; i++)
313 if (prim.NameValues[i].Name == "AttachItemID")
315 return (UUID)prim.NameValues[i].Value.ToString();
322 /// Is an inventory item currently attached
324 /// <param name="attachments">List of root prims that are attached to our avatar</param>
325 /// <param name="item">Inventory item to check</param>
326 /// <returns>True if the inventory item is attached to avatar</returns>
327 public static bool IsAttached(List<Primitive> attachments, InventoryItem item)
329 foreach (Primitive prim in attachments)
331 if (GetAttachmentItem(prim) == item.UUID)
341 /// Attach an inventory item
343 /// <param name="item">Item to be attached</param>
344 /// <param name="point">Attachment point</param>
345 /// <param name="replace">Replace existing attachment at that point first?</param>
346 public void Attach(InventoryItem item, AttachmentPoint point, bool replace)
348 Client.Appearance.Attach(item, point, replace);
349 if (COF == null) return;
351 bool linkExists = false;
354 linkExists = null != ContentLinks.Find(itemLink => itemLink.AssetUUID == item.UUID);
358 Client.Inventory.CreateLink(COF.UUID, item, (success, newItem) =>
364 ContentLinks.Add(newItem);
372 /// Remove a link to specified inventory item
374 /// <param name="itemID">ID of the target inventory item for which we want link to be removed</param>
375 public void RemoveLink(UUID itemID)
377 if (COF == null) return;
381 InventoryItem attachment = ContentLinks.Find(itemLink => itemLink.AssetUUID == itemID);
382 if (attachment != null)
384 Client.Inventory.RemoveItem(attachment.UUID);
385 ContentLinks.Remove(attachment);
391 /// Remove attachment
393 /// <param name="item">>Inventory item to be detached</param>
394 public void Detach(InventoryItem item)
396 Client.Appearance.Detach(item);
397 RemoveLink(item.UUID);
399 #endregion Public methods