/*************************************************************************** The Disc Image Chef ---------------------------------------------------------------------------- Filename : DumpAttachmentCommand.cs Version : 1.0.326 Author(s) : Natalia Portillo Component : NatiBot Revision : r326 Last change by : Natalia Portillo Date : 2010/01/01 --[ License ] -------------------------------------------------------------- This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ---------------------------------------------------------------------------- Copyright (C) 2008-2014 Claunia.com ****************************************************************************/ namespace bot.Commands { using bot; using OpenMetaverse; using OpenMetaverse.Utilities; using System; using System.Text; using System.Collections.Generic; using System.IO; using System.Threading; using OpenMetaverse.StructuredData; using OpenMetaverse.Assets; public class DumpAttachmentCommand : Command { List Textures = new List(); AutoResetEvent GotPermissionsEvent = new AutoResetEvent(false); Primitive.ObjectProperties Properties; bool GotPermissions = false; UUID SelectedObject = UUID.Zero; Dictionary PrimsWaiting = new Dictionary(); AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); private string DestinationDirectory = null; public DumpAttachmentCommand(SecondLifeBot SecondLifeBot) { SecondLifeBot.Objects.ObjectPropertiesFamily += new EventHandler(Objects_OnObjectPropertiesFamily); SecondLifeBot.Objects.ObjectProperties += new EventHandler(Objects_OnObjectProperties); SecondLifeBot.Avatars.ViewerEffectPointAt += new EventHandler(Avatars_ViewerEffectPointAt); base.Client = SecondLifeBot; base.Name = "dumpattachment"; base.Description = bot.Localization.clResourceManager.getText("Commands.DumpAttachment.Description") + " " + bot.Localization.clResourceManager.getText("Commands.DumpAttachment.Usage"); } public override string Execute(string[] args, UUID fromAgentID, bool fromSL) { StringBuilder builder = new StringBuilder(); if (args.Length < 2) { return bot.Localization.clResourceManager.getText("Commands.DumpAttachment.Usage"); } switch (args[1]) { // Chest case "Chest": break; // Skull case "Skull": break; // Left shoulder case "LeftShoulder": break; // Right shoulder case "RightShoulder": break; // Left hand case "LeftHand": break; // Right hand case "RightHand": break; // Left foot case "LeftFoot": break; // Right foot case "RightFoot": break; // Spine case "Spine": break; // Pelvis case "Pelvis": break; // Mouth case "Mouth": break; // Chin case "Chin": break; // Left ear case "LeftEar": break; // Right ear case "RightEar": break; // Left eyeball case "LeftEyeball": break; // Right eyeball case "RightEyeball": break; // Nose case "Nose": break; // Right upper arm case "RightUpperArm": break; // Right forearm case "RightForearm": break; // Left upper arm case "LeftUpperArm": break; // Left forearm case "LeftForearm": break; // Right hip case "RightHip": break; // Right upper leg case "RightUpperLeg": break; // Right lower leg case "RightLowerLeg": break; // Left hip case "LeftHip": break; // Left upper leg case "LeftUpperLeg": break; // Left lower leg case "LeftLowerLeg": break; // Stomach case "Stomach": break; // Left pectoral case "LeftPec": break; // Right pectoral case "RightPec": break; // Emerald viewer extra attachment points // Chest 2 case "Chest2": break; // Skull 2 case "Skull2": break; // Left shoulder 2 case "LeftShoulder2": break; // Right shoulder 2 case "RightShoulder2": break; // Left hand 2 case "LeftHand2": break; // Right hand 2 case "RightHand2": break; // Left foot 2 case "LeftFoot2": break; // Right foot 2 case "RightFoot2": break; // Spine 2 case "Spine2": break; // Pelvis 2 case "Pelvis2": break; // Mouth 2 case "Mouth2": break; // Chin 2 case "Chin2": break; // Left ear 2 case "LeftEar2": break; // Right ear 2 case "RightEar2": break; // Left eyeball 2 case "LeftEyeball2": break; // Right eyeball 2 case "RightEyeball2": break; // Nose 2 case "Nose2": break; // Right upper arm 2 case "RightUpperArm2": break; // Right forearm 2 case "RightForearm2": break; // Left upper arm 2 case "LeftUpperArm2": break; // Left forearm 2 case "LeftForearm2": break; // Right hip 2 case "RightHip2": break; // Right upper leg 2 case "RightUpperLeg2": break; // Right lower leg 2 case "RightLowerLeg2": break; // Left hip 2 case "LeftHip2": break; // Left upper leg 2 case "LeftUpperLeg2": break; // Left lower leg 2 case "LeftLowerLeg2": break; // Stomach 2 case "Stomach2": break; // Left pectoral 2 case "LeftPec2": break; // Right pectoral 2 case "RightPec2": break; // Left Knee case "LeftKnee": break; // Right Knee case "RightKnee": break; // Bridge case "Bridge": break; default: return bot.Localization.clResourceManager.getText("Commands.DumpAttachment.Invalid"); } Avatar av = base.Client.Network.CurrentSim.ObjectsAvatars.Find( delegate(Avatar a) { return a.ID.Equals((UUID)args[0]); } ); Program.NBStats.AddStatData(String.Format("{0}: {1} dumping attachment {2} of {3}.", DateTime.Now.ToString(), Client, args[1], args[0])); List list = base.Client.Network.CurrentSim.ObjectsPrimitives.FindAll(delegate(Primitive prim) { return prim.ParentID == av.LocalID; }); for (int i = 0; i < list.Count; i++) { Primitive primitive = list[i]; NBAttachmentPoint point = StateToAttachmentPoint(primitive.PrimData.State); if (point.ToString() == args[1]) { bool result; if (args[1] == "false") { result = ExportAttachment(primitive.ID, primitive.LocalID, point.ToString(), (UUID)args[0], false); } else { result = ExportAttachment(primitive.ID, primitive.LocalID, point.ToString(), (UUID)args[0], true); } if (result) { builder.AppendLine(string.Format(bot.Localization.clResourceManager.getText("Commands.DumpAttachment.Success"), new object[] { point })); } else { builder.AppendLine(string.Format(bot.Localization.clResourceManager.getText("Commands.DumpAttachment.Fail"), new object[] { point })); } } } DestinationDirectory = null; //builder.AppendLine("Exportados " + list.Count + " objetos"); return builder.ToString(); } public string CreateFileName(string AttachmentPointName, string PrimName) { string corrected_PrimName; string FinalName; if (PrimName == "") corrected_PrimName = "Object"; else corrected_PrimName = PrimName; corrected_PrimName = corrected_PrimName.Replace(" ", "_"); corrected_PrimName = corrected_PrimName.Replace(":", ";"); corrected_PrimName = corrected_PrimName.Replace("*", "+"); corrected_PrimName = corrected_PrimName.Replace("|", "I"); corrected_PrimName = corrected_PrimName.Replace("\\", "["); corrected_PrimName = corrected_PrimName.Replace("/", "]"); corrected_PrimName = corrected_PrimName.Replace("?", "¿"); corrected_PrimName = corrected_PrimName.Replace(">", "}"); corrected_PrimName = corrected_PrimName.Replace("<", "{"); corrected_PrimName = corrected_PrimName.Replace("\"", "'"); corrected_PrimName = corrected_PrimName.Replace("\n", " "); FinalName = corrected_PrimName + " (" + AttachmentPointName + ").xml"; return FinalName; } private void Assets_OnImageReceived(TextureRequestState state, AssetTexture asset) { string TextureDestination; if (DestinationDirectory == null) TextureDestination = "attachments/Textures/"; else TextureDestination = DestinationDirectory + "Textures/"; if (!Directory.Exists(TextureDestination)) Directory.CreateDirectory(TextureDestination); if (state == TextureRequestState.Finished && Textures.Contains(asset.AssetID)) { lock (Textures) Textures.Remove(asset.AssetID); if (state == TextureRequestState.Finished) { try { File.WriteAllBytes(TextureDestination + asset.AssetID + ".jp2", asset.AssetData); } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } if (asset.Decode()) { try { File.WriteAllBytes(TextureDestination + asset.AssetID + ".tga", asset.Image.ExportTGA()); } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); } } else { bot.Console.WriteLine(bot.Localization.clResourceManager.getText("Assets.Image.FailDecode"), asset.AssetID); } bot.Console.WriteLine(bot.Localization.clResourceManager.getText("Assets.Image.ImageDownloaded"), asset.AssetID); } else { bot.Console.WriteLine(bot.Localization.clResourceManager.getText("Assets.Image.FailDownload"), asset.AssetID, state); } } } void Avatars_ViewerEffectPointAt(object sender, ViewerEffectPointAtEventArgs e) { if (e.SourceID == Client.MasterKey) { //Client.DebugLog("Master is now selecting " + targetID.ToString()); SelectedObject = e.TargetID; } } public static NBAttachmentPoint StateToAttachmentPoint(uint state) { const uint ATTACHMENT_MASK = 0xF0; uint fixedState = (((byte)state & ATTACHMENT_MASK) >> 4) | (((byte)state & ~ATTACHMENT_MASK) << 4); return (NBAttachmentPoint)fixedState; } private static bool CompareLocalIDs(uint id, uint SearchedID) { if (id == SearchedID) { return true; } else { return false; } } private bool ExportAttachment(UUID ObjectUUID, uint LocalID, string AttachmentPosition, UUID AvatarID, bool DumpImages) { Predicate match = null; UUID id; //UUID.TryParse(ObjectUUID, out id); id = ObjectUUID; Primitive primitive = base.Client.Network.CurrentSim.ObjectsPrimitives.Find(delegate(Primitive prim) { return prim.ID == id; }); if (primitive != null) { uint localid = LocalID; base.Client.Objects.SelectObject(base.Client.Network.CurrentSim, LocalID); base.Client.Objects.RequestObjectPropertiesFamily(base.Client.Network.CurrentSim, id); this.GotPermissionsEvent.WaitOne(0x2710, false); #if !DEBUG if (!GotPermissions) { //return "Couldn't fetch permissions for the requested object, try again"; } else { GotPermissions = false; if (Properties.OwnerID != Client.Self.AgentID && Properties.OwnerID != Client.MasterKey || Properties.Permissions.EveryoneMask != PermissionMask.All) { return false; } } #endif this.GotPermissions = false; if (match == null) { match = delegate(Primitive prim) { if (prim.LocalID != localid) { return prim.ParentID == localid; } return true; }; } List objects = base.Client.Network.CurrentSim.ObjectsPrimitives.FindAll(match); List objects2 = new List(); bool complete = RequestObjectProperties(objects2, 250); if (!complete) { bot.Console.WriteLine(bot.Localization.clResourceManager.getText("Commands.DumpAttachment.NotProperties")); foreach (UUID uuid in PrimsWaiting.Keys) bot.Console.WriteLine(uuid.ToString()); } List ObjectsIDs = new List(); for (int j = 0; j < objects.Count; j++) { ObjectsIDs.Add(objects[j].LocalID); } for (int j = 0; j < objects.Count; j++) { base.Client.Objects.SelectObject(base.Client.Network.CurrentSim, objects[j].LocalID); } for (int j = 0; j < objects.Count; j++) { Primitive IntermediatePrimitive; IntermediatePrimitive = objects[j]; if (ObjectsIDs.FindIndex(delegate(uint lid) { return lid == IntermediatePrimitive.ParentID; }) == -1) { IntermediatePrimitive.ParentID = 0; } objects2.Add(IntermediatePrimitive); } for (int j = 0; j < objects.Count; j++) { base.Client.Objects.DeselectObject(base.Client.Network.CurrentSim, objects[j].LocalID); } string output = OSDParser.SerializeLLSDXmlString(Helpers.PrimListToOSD(objects2)); try { string AvatarName; if (DestinationDirectory == null) { if (!this.Client.key2Name(AvatarID, out AvatarName)) AvatarName = AvatarID.ToString(); DestinationDirectory = "./attachments/" + AvatarName + "_" + System.DateTime.Now.Year.ToString() + System.DateTime.Now.Month.ToString() + System.DateTime.Now.Day.ToString() + System.DateTime.Now.Hour.ToString() + //System.DateTime.Now.Minute.ToString() + //System.DateTime.Now.Second.ToString() + "/"; } string RealFileName; if (objects[0].Properties != null) RealFileName = CreateFileName(AttachmentPosition, objects[0].Properties.Name); else RealFileName = CreateFileName(AttachmentPosition, "Object"); if (!Directory.Exists(DestinationDirectory)) Directory.CreateDirectory(DestinationDirectory); File.WriteAllText(DestinationDirectory + RealFileName, output); } catch (Exception e) { base.Client.Objects.DeselectObject(base.Client.Network.CurrentSim, LocalID); bot.Console.WriteLine(e.Message); return false; } bot.Console.WriteLine(bot.Localization.clResourceManager.getText("Commands.DumpAttachment.Exported"), objects2.Count, DestinationDirectory, AttachmentPosition); // Create a list of all of the textures to download List textureRequests = new List(); if (DumpImages == true) { lock (Textures) { for (int i = 0; i < objects2.Count; i++) { Primitive prim = objects2[i]; if (prim.Textures.DefaultTexture.TextureID != Primitive.TextureEntry.WHITE_TEXTURE && !Textures.Contains(prim.Textures.DefaultTexture.TextureID)) { Textures.Add(prim.Textures.DefaultTexture.TextureID); } for (int j = 0; j < prim.Textures.FaceTextures.Length; j++) { if (prim.Textures.FaceTextures[j] != null && prim.Textures.FaceTextures[j].TextureID != Primitive.TextureEntry.WHITE_TEXTURE && !Textures.Contains(prim.Textures.FaceTextures[j].TextureID)) { Textures.Add(prim.Textures.FaceTextures[j].TextureID); } } if (prim.Sculpt != null) { if (prim.Sculpt.SculptTexture != UUID.Zero && !Textures.Contains(prim.Sculpt.SculptTexture)) { Textures.Add(prim.Sculpt.SculptTexture); } } } // Create a request list from all of the images for (int i = 0; i < Textures.Count; i++) textureRequests.Add(new ImageRequest(Textures[i], ImageType.Normal, 1013000.0f, 0)); } // Download all of the textures in the export list foreach (ImageRequest request in textureRequests) { base.Client.Assets.RequestImage(request.ImageID, request.Type, Assets_OnImageReceived); } } base.Client.Objects.DeselectObject(base.Client.Network.CurrentSim, LocalID); return true; //return ("XML exported, began downloading " + this.Textures.Count + " textures"); } //return string.Concat(new object[] { "Couldn't find UUID ", id.ToString(), " in the ", base.Client.Network.CurrentSim.ObjectsPrimitives.Count, "objects currently indexed in the current simulator" }); return false; } void Objects_OnObjectPropertiesFamily(object sender, ObjectPropertiesFamilyEventArgs e) { Properties = new Primitive.ObjectProperties(); Properties.SetFamilyProperties(e.Properties); GotPermissions = true; GotPermissionsEvent.Set(); } void Objects_OnObjectProperties(object sender, ObjectPropertiesEventArgs e) { lock (PrimsWaiting) { PrimsWaiting.Remove(e.Properties.ObjectID); if (PrimsWaiting.Count == 0) AllPropertiesReceived.Set(); } } private bool RequestObjectProperties(List objects, int msPerRequest) { // Create an array of the local IDs of all the prims we are requesting properties for uint[] localids = new uint[objects.Count]; lock (PrimsWaiting) { PrimsWaiting.Clear(); for (int i = 0; i < objects.Count; ++i) { localids[i] = objects[i].LocalID; PrimsWaiting.Add(objects[i].ID, objects[i]); } } Client.Objects.SelectObjects(Client.Network.CurrentSim, localids); return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false); } } }