/// <summary> /// Get a pronouncable form of each wearable type. /// </summary> /// <param name="item"></param> /// <returns></returns> string WearableType(InventoryWearable item) { switch (item.WearableType) { case OpenMetaverse.WearableType.Shirt: return("shirt"); case OpenMetaverse.WearableType.Pants: return("pants"); case OpenMetaverse.WearableType.Skirt: return("skirt"); case OpenMetaverse.WearableType.Shoes: return("shoes"); case OpenMetaverse.WearableType.Jacket: return("jacket"); case OpenMetaverse.WearableType.Socks: return("socks"); case OpenMetaverse.WearableType.Undershirt: return("undershirt"); case OpenMetaverse.WearableType.Underpants: return("underpants"); case OpenMetaverse.WearableType.Skin: return("skin"); case OpenMetaverse.WearableType.Eyes: return("eyes"); case OpenMetaverse.WearableType.Gloves: return("gloves"); case OpenMetaverse.WearableType.Hair: return("hair"); case OpenMetaverse.WearableType.Shape: return("body shape"); default: return("clothes"); } }
/// <summary> /// Add a single wearable to your outfit, replacing if nessesary. /// </summary> /// <param name="wearable"></param> public void Wear(InventoryWearable wearable) { List <InventoryWearable> x = new List <InventoryWearable>(); x.Add(wearable); Wear(x); }
void Inventory_ItemReceived(object sender, ItemReceivedEventArgs e) { var links = ContentLinks(); bool partOfCOF = links.Any(cofItem => cofItem.AssetUUID == e.Item.UUID); if (partOfCOF) { lock (Content) { Content[e.Item.UUID] = e.Item; } } if (Content.Count != links.Count) { return; } 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())); ; } } } }
/// <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 { AddLink(item, string.Empty); } }
/// <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 = $"@{(int) w.WearableType}{layer:00}"; AddLink(item, desc); } else { AddLink(item, string.Empty); } }
/// <summary> /// Equivalent to the SL "Replace Outfit" command. All clothing is removed, and replaced with wearables in given folder. Body wearables will be replaced if provided. /// </summary> /// <param name="outfitFolder">Contains the wearable items to put on.</param> /// <param name="TimeOut">How long to wait for outfit directory information to download</param> public void WearOutfit(InventoryFolder outfitFolder, int TimeOut) { // Refresh download of outfit folder if (!outfitFolder.RequestDownloadContents(false).RequestComplete.WaitOne(TimeOut, false)) { Console.WriteLine("An error occured while downloads the folder contents of : " + outfitFolder.Name); } // Make sure we have some Wearable Data to start with. if ((AgentWearablesData == null) || (AgentWearablesData.Length == 0)) { GetWearables(); } // Flush the cached clothing wearables so we can redefine them for (byte i = 4; i <= 12; i++) { AgentWearablesData[i].ItemID = LLUUID.Zero; AgentWearablesData[i].AssetID = LLUUID.Zero; } // Replace with wearables from Outfit folder foreach (InventoryBase ib in outfitFolder.GetContents()) { if (ib is InventoryWearable) { InventoryWearable iw = (InventoryWearable)ib; byte type = ((AssetWearable)iw.Asset).TypeFromAsset; AgentWearablesData[type].ItemID = iw.ItemID; AgentWearablesData[type].AssetID = iw.AssetID; } } // Create AgentIsNowWearing Packet, and send it SendAgentIsNowWearing(); // Update local Appearance Info GetAvatarAppearanceInfoFromWearableAssets(); // Send updated AgentSetAppearance to the grid SendAgentSetAppearance(); }
/// <summary> /// Add a single wearable to your outfit, replacing if nessesary. /// </summary> /// <param name="wearable"></param> public void Wear(InventoryWearable wearable) { List<InventoryWearable> x = new List<InventoryWearable>(); x.Add(wearable); Wear(x); }
/// <summary> /// Equivalent to the SL "Replace Outfit" command. All clothing is removed, and replaced with wearables in given folder. Body wearables will be replaced if provided. /// </summary> /// <param name="outfitFolder">Contains the wearable items to put on.</param> /// <param name="TimeOut">How long to wait for outfit directory information to download</param> public void WearOutfit(InventoryFolder outfitFolder, int TimeOut, bool removeExistingAttachments) { // Refresh download of outfit folder if (!outfitFolder.RequestDownloadContents(false, false, true).RequestComplete.WaitOne(TimeOut, false)) { Client.Log("Outfit not changed. An error occured while downloads the folder contents of : " + outfitFolder.Name, Helpers.LogLevel.Error); return; } // Make sure we have some Wearable Data to start with. if (AgentWearablesSignal.WaitOne(1000, false) == false) { Client.Log("You must have set appearance at least once, before calling WearOutfit(). AgentWearablesSignal not set.", Helpers.LogLevel.Error); return; } // Flush the cached clothing wearables so we can redefine them for (byte i = 4; i <= 12; i++) { AgentWearablesData[i].ItemID = LLUUID.Zero; AgentWearablesData[i].AssetID = LLUUID.Zero; } List <InventoryItem> attachments = new List <InventoryItem>(); // Replace with wearables from Outfit folder foreach (InventoryBase ib in outfitFolder.GetContents()) { if (ib is InventoryWearable) { try { InventoryWearable iw = (InventoryWearable)ib; Client.Log("Retrieving asset for " + iw.Name + "(" + iw.AssetID + ")", Helpers.LogLevel.Info); AssetWearable.AppearanceLayerType AppearanceLayer = ((AssetWearable)iw.Asset).AppearanceLayer; Client.Log("Adding skin/clothing layer for " + AppearanceLayer, Helpers.LogLevel.Info); AgentWearablesData[(byte)AppearanceLayer].ItemID = iw.ItemID; AgentWearablesData[(byte)AppearanceLayer].AssetID = iw.AssetID; } catch (Exception e) { Client.Log("Asset for " + ib._Name + " unavailable: " + e.Message, Helpers.LogLevel.Error); } } else if (ib is InventoryItem) { InventoryItem ii = (InventoryItem)ib; attachments.Add(ii); } } // Change attachments AddAttachments(attachments, removeExistingAttachments); // Create AgentIsNowWearing Packet, and send it SendAgentIsNowWearing(); // Send updated AgentSetAppearance to the grid SendAgentSetAppearance(); }
private void FillItemProperties() { txtItemName.Text = item.Name; if (item.AssetUUID != UUID.Zero) { txtUUID.Text = item.AssetUUID.ToString(); } else { txtUUID.Text = item.UUID.ToString(); txtItemUUID.Text = item.UUID.ToString(); } if (item.UUID != UUID.Zero) { txtItemUUID.Text = item.UUID.ToString(); } txtItemCreator.Text = txtItemOwner.Text = "Retreiving name..."; txtItemDescription.Text = item.Description; List <UUID> avIDs = new List <UUID>(); avIDs.Add(item.CreatorID); avIDs.Add(item.OwnerID); client.Avatars.RequestAvatarNames(avIDs); // Get permissions if ((item.Permissions.NextOwnerMask & PermissionMask.Modify) == PermissionMask.Modify) { checkBox1.Checked = true; txtItemDescription.ReadOnly = false; } else { checkBox1.Checked = false; txtItemDescription.ReadOnly = true; } if ((item.Permissions.NextOwnerMask & PermissionMask.Copy) == PermissionMask.Copy) { checkBox2.Checked = true; } else { checkBox2.Checked = false; } if ((item.Permissions.NextOwnerMask & PermissionMask.Transfer) == PermissionMask.Transfer) { checkBox3.Checked = true; } else { checkBox3.Checked = false; } // Set permission checboxes if ((item.Permissions.OwnerMask & PermissionMask.Modify) == PermissionMask.Modify) { checkBox1.Enabled = true; txtItemDescription.ReadOnly = false; } else { checkBox1.Enabled = false; txtItemDescription.ReadOnly = true; } if ((item.Permissions.OwnerMask & PermissionMask.Copy) == PermissionMask.Copy) { checkBox2.Enabled = true; } else { checkBox2.Enabled = false; } if ((item.Permissions.OwnerMask & PermissionMask.Transfer) == PermissionMask.Transfer) { checkBox3.Enabled = true; btnGive.Enabled = true; } else { checkBox3.Enabled = false; btnGive.Enabled = false; } label11.Visible = true; switch (item.InventoryType) { case InventoryType.Object: InventoryObjectConsole objectConsole = new InventoryObjectConsole(instance, item); btnDetach.Text = "Detach"; objectConsole.Dock = DockStyle.Fill; pnlItemTypeProp.Controls.Add(objectConsole); //objectConsole.Dispose(); break; case InventoryType.Notecard: InventoryNotecardConsole notecardConsole = new InventoryNotecardConsole(instance, item); notecardConsole.Dock = DockStyle.Fill; pnlItemTypeProp.Controls.Add(notecardConsole); label11.Visible = false; //notecardConsole.Dispose(); break; case InventoryType.LSL: InventoryScriptConsole scriptConsole = new InventoryScriptConsole(instance, item); scriptConsole.Dock = DockStyle.Fill; pnlItemTypeProp.Controls.Add(scriptConsole); label11.Visible = false; //scriptConsole.Dispose(); break; case InventoryType.Snapshot: InventoryImageConsole imageConsole = new InventoryImageConsole(instance, item); imageConsole.Dock = DockStyle.Fill; pnlItemTypeProp.Controls.Add(imageConsole); label11.Visible = false; break; case InventoryType.Wearable: btnDetach.Text = "Take off"; break; case InventoryType.Attachment: btnDetach.Text = "Detach"; break; case InventoryType.Landmark: label11.Visible = false; break; case InventoryType.Animation: InventoryAnimationConsole animationConsole = new InventoryAnimationConsole(instance, item); animationConsole.Dock = DockStyle.Fill; pnlItemTypeProp.Controls.Add(animationConsole); label11.Visible = false; break; case InventoryType.Texture: imageConsole = new InventoryImageConsole(instance, item); imageConsole.Dock = DockStyle.Fill; pnlItemTypeProp.Controls.Add(imageConsole); label11.Visible = false; break; case InventoryType.Gesture: InventoryGestureConsol gestureConsole = new InventoryGestureConsol(instance, item); gestureConsole.Dock = DockStyle.Fill; pnlItemTypeProp.Controls.Add(gestureConsole); label11.Visible = false; break; } if (item.InventoryType == InventoryType.Wearable) { InventoryWearable werbl = item as InventoryWearable; if (item.ParentUUID == instance.CoF.UUID) { InventoryItem wItem = AInventoryItem(item); werbl = wItem as InventoryWearable; label9.Text = "Wearable type: " + werbl.WearableType.ToString(); } else { label9.Text = "Wearable type: " + werbl.WearableType.ToString(); } } else { //if (item.ParentUUID == instance.CoF.UUID) //{ //} //else //{ // label9.Text = string.Empty; //} label9.Text = "Asset type: " + item.AssetType.ToString(); } if ((item.Permissions.OwnerMask & PermissionMask.Modify) != PermissionMask.Modify) { checkBox1.Enabled = checkBox2.Enabled = checkBox3.Enabled = false; } fLoading = false; }
/// <summary> /// Returned in response to a InventoryDescendantRequest. Contains information about the /// contents of a folder. /// </summary> /// <seealso cref="InventoryManager.RequestFolder"/> /// <param name="packet"></param> /// <param name="simulator"></param> 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; // 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 // the "filler" block will not have a name if (itemBlock.Name.Length != 0) { iDescendentsReceivedThisBlock++; if (itemBlock.ItemID == LLUUID.Zero) { // this shouldn't ever happen, unless you've uploaded an invalid item // to yourself while developping inventory code :-( } else { invItem = new InventoryItem(this, itemBlock); InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invItem.FolderID]; if (ifolder._Contents.Contains(invItem) == false) { if ((invItem.InvType == 7) && (invItem.Type == Asset.ASSET_TYPE_NOTECARD)) { InventoryItem temp = new InventoryNotecard(this, invItem); invItem = temp; } if ((invItem.InvType == 0) && (invItem.Type == Asset.ASSET_TYPE_IMAGE)) { InventoryItem temp = new InventoryImage(this, invItem); invItem = temp; } if ((invItem.InvType == 18) && ( (invItem.Type == Asset.ASSET_TYPE_WEARABLE_BODY) || (invItem.Type == Asset.ASSET_TYPE_WEARABLE_CLOTHING) ) ) { InventoryItem temp = new InventoryWearable(this, invItem); invItem = temp; } ifolder._Contents.Add(invItem); } } } } foreach (InventoryDescendentsPacket.FolderDataBlock folderBlock in reply.FolderData) { String name = System.Text.Encoding.UTF8.GetString(folderBlock.Name).Trim().Replace("\0", ""); LLUUID folderid = folderBlock.FolderID; LLUUID parentid = folderBlock.ParentID; // unused? sbyte type = folderBlock.Type; // There is always an folder block, even if there isn't any folders // the "filler" block will not have a name if (folderBlock.Name.Length != 0) { invFolder = new InventoryFolder(this, name, folderid, parentid); iDescendentsReceivedThisBlock++; // Add folder to Parent InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invFolder.ParentID]; if (ifolder._Contents.Contains(invFolder) == false) { ifolder._Contents.Add(invFolder); } // Add folder to UUID Lookup htFoldersByUUID[invFolder.FolderID] = invFolder; // Do we recurse? if (dr.Recurse) { // It's not the root, should be safe to "recurse" if (!invFolder.FolderID.Equals(slClient.Self.InventoryRootFolderUUID)) { bool alreadyQueued = false; foreach (DownloadRequest_Folder adr in alFolderRequestQueue) { if (adr.FolderID == invFolder.FolderID) { alreadyQueued = true; break; } } if (!alreadyQueued) { alFolderRequestQueue.Add(new DownloadRequest_Folder(invFolder.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. 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 dr.Expected = iDescendentsExpected; dr.Received += iDescendentsReceivedThisBlock; dr.LastReceivedAtTick = Environment.TickCount; if (dr.Received >= dr.Expected) { // Looks like after updating, we have all the descendents, // remove from folder status. FolderDownloadStatus.Remove(uuidFolderID); dr.RequestComplete.Set(); } else { FolderDownloadStatus[uuidFolderID] = dr; } } }
/// <summary> /// Returned in response to a FetchInventoryDescendents request. Contains information about the /// contents of a folder. /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> public void InventoryDescendentsHandler(Packet packet, Simulator simulator) { InventoryDescendentsPacket reply = (InventoryDescendentsPacket)packet; // The UUID of this folder. LLUUID uuidFolderID = reply.AgentData.FolderID; // Wait until it's safe to be looking at what is currently downloading. CurrentlyDownloadingMutex.WaitOne(); // Make sure this request matches the one we believe is the currently downloading request if (((CurrentlyDownloadingRequest != null) && (CurrentlyDownloadingRequest.FolderID != uuidFolderID)) || (CurrentlyDownloadingRequest == null)) { // Release so that we can let other things look at and modify what is currently downloading. CurrentlyDownloadingMutex.ReleaseMutex(); // Log problem LogDescendantQueueEvent("Unexpected descendent packet for folder: " + uuidFolderID.ToStringHyphenated()); // Just discard this packet... return; } // Get the Inventory folder that we'll be updating InventoryFolder InvFolderUpdating = (InventoryFolder)FoldersByUUID[uuidFolderID]; // Update Inventory Manager's last tick point, used for timeouts and such // LastPacketRecievedAtTick = Environment.TickCount; // Used to count the number of descendants received to see if we're finished or not. int iDescendentsExpected = reply.AgentData.Descendents; int iDescendentsReceivedThisBlock = 0; #region Handle Child Items foreach (InventoryDescendentsPacket.ItemDataBlock itemBlock in reply.ItemData) { // There is always an item block, even if there isn't any items // the "filler" block will not have a name if (itemBlock.Name.Length != 0) { iDescendentsReceivedThisBlock++; if (itemBlock.ItemID == LLUUID.Zero) { // this shouldn't ever happen, unless you've uploaded an invalid item // to yourself while developping inventory code :-( } else { InventoryItem TempInvItem = new InventoryItem(this, itemBlock); if (InvFolderUpdating._Contents.Contains(TempInvItem) == false) { #region Create an instance of the appriopriate Inventory class if ((TempInvItem.InvType == 7) && (TempInvItem.Type == (sbyte)Asset.AssetType.Notecard)) { InventoryItem temp = new InventoryNotecard(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 3) && (TempInvItem.Type == (sbyte)Asset.AssetType.Landmark)) { InventoryItem temp = new InventoryLandmark(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 0) && (TempInvItem.Type == (sbyte)Asset.AssetType.Texture)) { InventoryItem temp = new InventoryImage(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 10) && (TempInvItem.Type == (sbyte)Asset.AssetType.LSLText)) { InventoryItem temp = new InventoryScript(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 18) && ( (TempInvItem.Type == (sbyte)Asset.AssetType.Bodypart) || (TempInvItem.Type == (sbyte)Asset.AssetType.Clothing) ) ) { InventoryItem temp = new InventoryWearable(this, TempInvItem); TempInvItem = temp; } #endregion InvFolderUpdating._Contents.Add(TempInvItem); } } } } #endregion #region Handle Child Folders foreach (InventoryDescendentsPacket.FolderDataBlock folderBlock in reply.FolderData) { String IncomingName = System.Text.Encoding.UTF8.GetString(folderBlock.Name).Trim().Replace("\0", ""); LLUUID IncomingFolderID = folderBlock.FolderID; LLUUID IncomingParentID = folderBlock.ParentID; sbyte IncomingType = folderBlock.Type; // There is always an folder block, even if there isn't any folders // the "filler" block will not have a name if (folderBlock.Name.Length != 0) { iDescendentsReceivedThisBlock++; // See if the Incoming Folder already exists locally if (FoldersByUUID.ContainsKey(IncomingFolderID)) { InventoryFolder existingFolder = FoldersByUUID[IncomingFolderID]; existingFolder._Name = IncomingName; existingFolder._Type = IncomingType; // Check if parent of existing is the same as the incoming if (!existingFolder.ParentID.Equals(IncomingParentID)) { // Remove existing from old parent if (FoldersByUUID.ContainsKey(existingFolder.ParentID)) { InventoryFolder ExistingParent = FoldersByUUID[existingFolder.ParentID]; if (ExistingParent._Contents.Contains(existingFolder)) { ExistingParent._Contents.Remove(existingFolder); } } // Set existings parent to new existingFolder._ParentID = IncomingParentID; // Connect existing folder to parent specified in new if (FoldersByUUID.ContainsKey(IncomingParentID)) { InventoryFolder ExistingParent = FoldersByUUID[IncomingParentID]; if (!ExistingParent._Contents.Contains(existingFolder)) { ExistingParent._Contents.Add(existingFolder); } } } } else { InventoryFolder TempInvFolder = new InventoryFolder(this, IncomingName, IncomingFolderID, IncomingParentID, IncomingType); // Add folder to Parent if (InvFolderUpdating._Contents.Contains(TempInvFolder) == false) { InvFolderUpdating._Contents.Add(TempInvFolder); } // Add folder to local cache lookup FoldersByUUID[TempInvFolder.FolderID] = TempInvFolder; } // Do we recurse? if (CurrentlyDownloadingRequest.Recurse) { // It's not the root, should be safe to "recurse" if (!IncomingFolderID.Equals(slClient.Self.InventoryRootFolderUUID)) { FolderRequestPrepend(IncomingFolderID, CurrentlyDownloadingRequest.Recurse, CurrentlyDownloadingRequest.FetchFolders, CurrentlyDownloadingRequest.FetchItems, CurrentlyDownloadingRequest.Name + "/" + IncomingName); } } } } #endregion // Update total number of descendants expected , and update the total downloaded CurrentlyDownloadingRequest.Expected = iDescendentsExpected; CurrentlyDownloadingRequest.Received += iDescendentsReceivedThisBlock; CurrentlyDownloadingRequest.LastReceivedAtTick = Environment.TickCount; if ((iDescendentsExpected > 1) && (iDescendentsReceivedThisBlock == 0)) { slClient.Log("Received an InventoryDescendant packet where it indicated that there should be at least 1 descendant, but none were present... [" + CurrentlyDownloadingRequest.Name + "]", Helpers.LogLevel.Warning); CurrentlyDownloadingRequest.Expected = 0; } if (LogDescendantQueue) { slClient.Log("Received packet for: " + CurrentlyDownloadingRequest.ToString(), Helpers.LogLevel.Info); } // Check if we're finished if (CurrentlyDownloadingRequest.Received >= CurrentlyDownloadingRequest.Expected) { LogDescendantQueueEvent("Done downloading request: " + CurrentlyDownloadingRequest); // Singal anyone that was waiting for this request to finish CurrentlyDownloadingRequest.RequestComplete.Set(); // Raise an event for anyone that cares to listen for downloaded folder events if (OnRequestDownloadFinishedEvent != null) { DownloadRequest_EventArgs e = new DownloadRequest_EventArgs(); e.DownloadRequest = CurrentlyDownloadingRequest; FireRequestDownloadFinishedEvent(InvFolderUpdating, e); } // Set Inventory Manager state to reflect that we're done with the current download CurrentlyDownloadingAFolder = false; CurrentlyDownloadingRequest = null; } // Release so that we can let other things look at and modify what is currently downloading. CurrentlyDownloadingMutex.ReleaseMutex(); // If there's any more download requests queued, grab one, and go FolderRequestBegin(); }