opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Linq;
32 using System.Reflection;
33 using System.Text;
34 using System.Text.RegularExpressions;
35 using System.Xml;
36 using log4net;
37 using Mono.Addins;
38 using NDesk.Options;
39 using Nini.Config;
40 using OpenMetaverse;
41 using OpenSim.Framework;
42 using OpenSim.Framework.Console;
43 using OpenSim.Framework.Monitoring;
44 using OpenSim.Region.Framework.Interfaces;
45 using OpenSim.Region.Framework.Scenes;
46 using OpenSim.Region.Framework.Scenes.Serialization;
47  
48 namespace OpenSim.Region.CoreModules.World.Objects.Commands
49 {
50 /// <summary>
51 /// A module that holds commands for manipulating objects in the scene.
52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ObjectCommandsModule")]
54 public class ObjectCommandsModule : INonSharedRegionModule
55 {
56 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57  
58 private Scene m_scene;
59 private ICommandConsole m_console;
60  
61 public string Name { get { return "Object Commands Module"; } }
62  
63 public Type ReplaceableInterface { get { return null; } }
64  
65 public void Initialise(IConfigSource source)
66 {
67 // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: INITIALIZED MODULE");
68 }
69  
70 public void PostInitialise()
71 {
72 // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: POST INITIALIZED MODULE");
73 }
74  
75 public void Close()
76 {
77 // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: CLOSED MODULE");
78 }
79  
80 public void AddRegion(Scene scene)
81 {
82 // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
83  
84 m_scene = scene;
85 m_console = MainConsole.Instance;
86  
87 m_console.Commands.AddCommand(
88 "Objects", false, "delete object owner",
89 "delete object owner <UUID>",
90 "Delete scene objects by owner",
91 "Command will ask for confirmation before proceeding.",
92 HandleDeleteObject);
93  
94 m_console.Commands.AddCommand(
95 "Objects", false, "delete object creator",
96 "delete object creator <UUID>",
97 "Delete scene objects by creator",
98 "Command will ask for confirmation before proceeding.",
99 HandleDeleteObject);
100  
101 m_console.Commands.AddCommand(
102 "Objects", false, "delete object id",
103 "delete object id <UUID-or-localID>",
104 "Delete a scene object by uuid or localID",
105 HandleDeleteObject);
106  
107 m_console.Commands.AddCommand(
108 "Objects", false, "delete object name",
109 "delete object name [--regex] <name>",
110 "Delete a scene object by name.",
111 "Command will ask for confirmation before proceeding.\n"
112 + "If --regex is specified then the name is treatead as a regular expression",
113 HandleDeleteObject);
114  
115 m_console.Commands.AddCommand(
116 "Objects", false, "delete object outside",
117 "delete object outside",
118 "Delete all scene objects outside region boundaries",
119 "Command will ask for confirmation before proceeding.",
120 HandleDeleteObject);
121  
122 m_console.Commands.AddCommand(
123 "Objects",
124 false,
125 "delete object pos",
126 "delete object pos <start-coord> to <end-coord>",
127 "Delete scene objects within the given area.",
128 ConsoleUtil.CoordHelp,
129 HandleDeleteObject);
130  
131 m_console.Commands.AddCommand(
132 "Objects",
133 false,
134 "show object id",
135 "show object id [--full] <UUID-or-localID>",
136 "Show details of a scene object with the given UUID or localID",
137 "The --full option will print out information on all the parts of the object.\n"
138 + "For yet more detailed part information, use the \"show part\" commands.",
139 HandleShowObjectById);
140  
141 m_console.Commands.AddCommand(
142 "Objects",
143 false,
144 "show object name",
145 "show object name [--full] [--regex] <name>",
146 "Show details of scene objects with the given name.",
147 "The --full option will print out information on all the parts of the object.\n"
148 + "For yet more detailed part information, use the \"show part\" commands.\n"
149 + "If --regex is specified then the name is treatead as a regular expression.",
150 HandleShowObjectByName);
151  
152 m_console.Commands.AddCommand(
153 "Objects",
154 false,
155 "show object pos",
156 "show object pos [--full] <start-coord> to <end-coord>",
157 "Show details of scene objects within the given area.",
158 "The --full option will print out information on all the parts of the object.\n"
159 + "For yet more detailed part information, use the \"show part\" commands.\n"
160 + ConsoleUtil.CoordHelp,
161 HandleShowObjectByPos);
162  
163 m_console.Commands.AddCommand(
164 "Objects",
165 false,
166 "show part id",
167 "show part id <UUID-or-localID>",
168 "Show details of a scene object part with the given UUID or localID", HandleShowPartById);
169  
170 m_console.Commands.AddCommand(
171 "Objects",
172 false,
173 "show part name",
174 "show part name [--regex] <name>",
175 "Show details of scene object parts with the given name.",
176 "If --regex is specified then the name is treated as a regular expression",
177 HandleShowPartByName);
178  
179 m_console.Commands.AddCommand(
180 "Objects",
181 false,
182 "show part pos",
183 "show part pos <start-coord> to <end-coord>",
184 "Show details of scene object parts within the given area.",
185 ConsoleUtil.CoordHelp,
186 HandleShowPartByPos);
187  
188 m_console.Commands.AddCommand(
189 "Objects",
190 false,
191 "dump object id",
192 "dump object id <UUID-or-localID>",
193 "Dump the formatted serialization of the given object to the file <UUID>.xml",
194 "e.g. dump object uuid c1ed6809-cc24-4061-a4c2-93082a2d1f1d will dump serialization to c1ed6809-cc24-4061-a4c2-93082a2d1f1d.xml\n"
195 + "To locate the UUID or localID in the first place, you need to use the other show object commands.\n"
196 + "If a local ID is given then the filename used is still that for the UUID",
197 HandleDumpObjectById);
198 }
199  
200 public void RemoveRegion(Scene scene)
201 {
202 // m_log.DebugFormat("[OBJECTS COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
203 }
204  
205 public void RegionLoaded(Scene scene)
206 {
207 // m_log.DebugFormat("[OBJECTS COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
208 }
209  
210 /// <summary>
211 /// Outputs the sogs to console.
212 /// </summary>
213 /// <param name='searchPredicate'></param>
214 /// <param name='showFull'>If true then output all part details. If false then output summary.</param>
215 private void OutputSogsToConsole(Predicate<SceneObjectGroup> searchPredicate, bool showFull)
216 {
217 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups().FindAll(searchPredicate);
218  
219 StringBuilder sb = new StringBuilder();
220  
221 foreach (SceneObjectGroup so in sceneObjects)
222 {
223 AddSceneObjectReport(sb, so, showFull);
224 sb.Append("\n");
225 }
226  
227 sb.AppendFormat("{0} object(s) found in {1}\n", sceneObjects.Count, m_scene.Name);
228  
229 m_console.OutputFormat(sb.ToString());
230 }
231  
232 private void OutputSopsToConsole(Predicate<SceneObjectPart> searchPredicate, bool showFull)
233 {
234 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups();
235 List<SceneObjectPart> parts = new List<SceneObjectPart>();
236  
237 sceneObjects.ForEach(so => parts.AddRange(Array.FindAll<SceneObjectPart>(so.Parts, searchPredicate)));
238  
239 StringBuilder sb = new StringBuilder();
240  
241 foreach (SceneObjectPart part in parts)
242 {
243 AddScenePartReport(sb, part, showFull);
244 sb.Append("\n");
245 }
246  
247 sb.AppendFormat("{0} parts found in {1}\n", parts.Count, m_scene.Name);
248  
249 m_console.OutputFormat(sb.ToString());
250 }
251  
252 private void HandleShowObjectById(string module, string[] cmdparams)
253 {
254 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
255 return;
256  
257 bool showFull = false;
258 OptionSet options = new OptionSet().Add("full", v => showFull = v != null );
259  
260 List<string> mainParams = options.Parse(cmdparams);
261  
262 if (mainParams.Count < 4)
263 {
264 m_console.OutputFormat("Usage: show object uuid <uuid>");
265 return;
266 }
267  
268 UUID uuid;
269 uint localId;
270 if (!ConsoleUtil.TryParseConsoleId(m_console, mainParams[3], out uuid, out localId))
271 return;
272  
273 SceneObjectGroup so;
274  
275 if (localId != ConsoleUtil.LocalIdNotFound)
276 so = m_scene.GetSceneObjectGroup(localId);
277 else
278 so = m_scene.GetSceneObjectGroup(uuid);
279  
280 if (so == null)
281 {
282 // m_console.OutputFormat("No part found with uuid {0}", objectUuid);
283 return;
284 }
285  
286 StringBuilder sb = new StringBuilder();
287 AddSceneObjectReport(sb, so, showFull);
288  
289 m_console.OutputFormat(sb.ToString());
290 }
291  
292 private void HandleShowObjectByName(string module, string[] cmdparams)
293 {
294 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
295 return;
296  
297 bool showFull = false;
298 bool useRegex = false;
299 OptionSet options = new OptionSet();
300 options.Add("full", v => showFull = v != null );
301 options.Add("regex", v => useRegex = v != null );
302  
303 List<string> mainParams = options.Parse(cmdparams);
304  
305 if (mainParams.Count < 4)
306 {
307 m_console.OutputFormat("Usage: show object name [--full] [--regex] <name>");
308 return;
309 }
310  
311 string name = mainParams[3];
312  
313 Predicate<SceneObjectGroup> searchPredicate;
314  
315 if (useRegex)
316 {
317 Regex nameRegex = new Regex(name);
318 searchPredicate = so => nameRegex.IsMatch(so.Name);
319 }
320 else
321 {
322 searchPredicate = so => so.Name == name;
323 }
324  
325 OutputSogsToConsole(searchPredicate, showFull);
326 }
327  
328 private void HandleShowObjectByPos(string module, string[] cmdparams)
329 {
330 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
331 return;
332  
333 bool showFull = false;
334 OptionSet options = new OptionSet().Add("full", v => showFull = v != null );
335  
336 List<string> mainParams = options.Parse(cmdparams);
337  
338 if (mainParams.Count < 5)
339 {
340 m_console.OutputFormat("Usage: show object pos [--full] <start-coord> to <end-coord>");
341 return;
342 }
343  
344 Vector3 startVector, endVector;
345  
346 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
347 return;
348  
349 Predicate<SceneObjectGroup> searchPredicate
350 = so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector);
351  
352 OutputSogsToConsole(searchPredicate, showFull);
353 }
354  
355 private void HandleShowPartById(string module, string[] cmdparams)
356 {
357 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
358 return;
359  
360 // bool showFull = false;
361 OptionSet options = new OptionSet();
362 // options.Add("full", v => showFull = v != null );
363  
364 List<string> mainParams = options.Parse(cmdparams);
365  
366 if (mainParams.Count < 4)
367 {
368 //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
369 m_console.OutputFormat("Usage: show part id <UUID-or-localID>");
370 return;
371 }
372  
373 UUID objectUuid;
374 uint localId;
375 if (!ConsoleUtil.TryParseConsoleId(m_console, mainParams[3], out objectUuid, out localId))
376 return;
377  
378 SceneObjectPart sop;
379 if (localId == ConsoleUtil.LocalIdNotFound)
380 sop = m_scene.GetSceneObjectPart(objectUuid);
381 else
382 sop = m_scene.GetSceneObjectPart(localId);
383  
384 if (sop == null)
385 {
386 // m_console.OutputFormat("No part found with uuid {0}", objectUuid);
387 return;
388 }
389  
390 StringBuilder sb = new StringBuilder();
391 AddScenePartReport(sb, sop, true);
392  
393 m_console.OutputFormat(sb.ToString());
394 }
395  
396 private void HandleShowPartByPos(string module, string[] cmdparams)
397 {
398 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
399 return;
400  
401 // bool showFull = false;
402 OptionSet options = new OptionSet();
403 // options.Add("full", v => showFull = v != null );
404  
405 List<string> mainParams = options.Parse(cmdparams);
406  
407 if (mainParams.Count < 5)
408 {
409 //m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
410 m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
411 return;
412 }
413  
414 string rawConsoleStartVector = mainParams[3];
415 Vector3 startVector;
416  
417 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
418 {
419 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
420 return;
421 }
422  
423 string rawConsoleEndVector = mainParams[5];
424 Vector3 endVector;
425  
426 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
427 {
428 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
429 return;
430 }
431  
432 OutputSopsToConsole(sop => Util.IsInsideBox(sop.AbsolutePosition, startVector, endVector), true);
433 }
434  
435 private void HandleShowPartByName(string module, string[] cmdparams)
436 {
437 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
438 return;
439  
440 // bool showFull = false;
441 bool useRegex = false;
442 OptionSet options = new OptionSet();
443 // options.Add("full", v => showFull = v != null );
444 options.Add("regex", v => useRegex = v != null );
445  
446 List<string> mainParams = options.Parse(cmdparams);
447  
448 if (mainParams.Count < 4)
449 {
450 m_console.OutputFormat("Usage: show part name [--regex] <name>");
451 //m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
452 return;
453 }
454  
455 string name = mainParams[3];
456  
457 Predicate<SceneObjectPart> searchPredicate;
458  
459 if (useRegex)
460 {
461 Regex nameRegex = new Regex(name);
462 searchPredicate = sop => nameRegex.IsMatch(sop.Name);
463 }
464 else
465 {
466 searchPredicate = sop => sop.Name == name;
467 }
468  
469 OutputSopsToConsole(searchPredicate, true);
470 }
471  
472 private void HandleDumpObjectById(string module, string[] cmdparams)
473 {
474 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
475 return;
476  
477 if (cmdparams.Length < 4)
478 {
479 m_console.OutputFormat("Usage: dump object id <UUID-or-localID>");
480 return;
481 }
482  
483 UUID objectUuid;
484 uint localId;
485 if (!ConsoleUtil.TryParseConsoleId(m_console, cmdparams[3], out objectUuid, out localId))
486 return;
487  
488 SceneObjectGroup so;
489 if (localId == ConsoleUtil.LocalIdNotFound)
490 so = m_scene.GetSceneObjectGroup(objectUuid);
491 else
492 so = m_scene.GetSceneObjectGroup(localId);
493  
494 if (so == null)
495 {
496 // m_console.OutputFormat("No part found with uuid {0}", objectUuid);
497 return;
498 }
499  
500 // In case we found it via local ID.
501 objectUuid = so.UUID;
502  
503 string fileName = string.Format("{0}.xml", objectUuid);
504  
505 if (!ConsoleUtil.CheckFileDoesNotExist(m_console, fileName))
506 return;
507  
508 using (XmlTextWriter xtw = new XmlTextWriter(fileName, Encoding.UTF8))
509 {
510 xtw.Formatting = Formatting.Indented;
511 SceneObjectSerializer.ToOriginalXmlFormat(so, xtw, true);
512 }
513  
514 m_console.OutputFormat("Object dumped to file {0}", fileName);
515 }
516  
517 /// <summary>
518 /// Append a scene object report to an input StringBuilder
519 /// </summary>
520 /// <returns></returns>
521 /// <param name='sb'></param>
522 /// <param name='so'</param>
523 /// <param name='showFull'>
524 /// If true then information on all parts of an object is appended.
525 /// If false then only summary information about an object is appended.
526 /// </param>
527 private StringBuilder AddSceneObjectReport(StringBuilder sb, SceneObjectGroup so, bool showFull)
528 {
529 if (showFull)
530 {
531 foreach (SceneObjectPart sop in so.Parts)
532 {
533 AddScenePartReport(sb, sop, false);
534 sb.Append("\n");
535 }
536 }
537 else
538 {
539 AddSummarySceneObjectReport(sb, so);
540 }
541  
542 return sb;
543 }
544  
545 private StringBuilder AddSummarySceneObjectReport(StringBuilder sb, SceneObjectGroup so)
546 {
547 ConsoleDisplayList cdl = new ConsoleDisplayList();
548 cdl.AddRow("Name", so.Name);
549 cdl.AddRow("Description", so.Description);
550 cdl.AddRow("Local ID", so.LocalId);
551 cdl.AddRow("UUID", so.UUID);
552 cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name));
553 cdl.AddRow("Parts", so.PrimCount);
554 cdl.AddRow("Flags", so.RootPart.Flags);
555  
556 return sb.Append(cdl.ToString());
557 }
558  
559 /// <summary>
560 /// Append a scene object part report to an input StringBuilder
561 /// </summary>
562 /// <returns></returns>
563 /// <param name='sb'></param>
564 /// <param name='sop'</param>
565 /// <param name='showFull'>
566 /// If true then information on each inventory item will be shown.
567 /// If false then only summary inventory information is shown.
568 /// </param>
569 private StringBuilder AddScenePartReport(StringBuilder sb, SceneObjectPart sop, bool showFull)
570 {
571 ConsoleDisplayList cdl = new ConsoleDisplayList();
572 cdl.AddRow("Name", sop.Name);
573 cdl.AddRow("Description", sop.Description);
574 cdl.AddRow("Local ID", sop.LocalId);
575 cdl.AddRow("UUID", sop.UUID);
576 cdl.AddRow("Location", string.Format("{0} @ {1}", sop.AbsolutePosition, sop.ParentGroup.Scene.Name));
577 cdl.AddRow(
578 "Parent",
579 sop.IsRoot ? "Is Root" : string.Format("{0} {1}", sop.ParentGroup.Name, sop.ParentGroup.UUID));
580 cdl.AddRow("Link number", sop.LinkNum);
581 cdl.AddRow("Flags", sop.Flags);
582  
583 if (showFull)
584 {
585 PrimitiveBaseShape s = sop.Shape;
586 cdl.AddRow("FlexiDrag", s.FlexiDrag);
587 cdl.AddRow("FlexiEntry", s.FlexiEntry);
588 cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ));
589 cdl.AddRow("FlexiGravity", s.FlexiGravity);
590 cdl.AddRow("FlexiSoftness", s.FlexiSoftness);
591 cdl.AddRow("HollowShape", s.HollowShape);
592 cdl.AddRow(
593 "LightColor",
594 string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
595 cdl.AddRow("LightCutoff", s.LightCutoff);
596 cdl.AddRow("LightEntry", s.LightEntry);
597 cdl.AddRow("LightFalloff", s.LightFalloff);
598 cdl.AddRow("LightIntensity", s.LightIntensity);
599 cdl.AddRow("LightRadius", s.LightRadius);
600 cdl.AddRow("Location (relative)", sop.RelativePosition);
601 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
602 cdl.AddRow("PathBegin", s.PathBegin);
603 cdl.AddRow("PathEnd", s.PathEnd);
604 cdl.AddRow("PathCurve", s.PathCurve);
605 cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
606 cdl.AddRow("PathRevolutions", s.PathRevolutions);
607 cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
608 cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
609 cdl.AddRow("FlexiDrag", s.PathSkew);
610 cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
611 cdl.AddRow("PathTwist", s.PathTwist);
612 cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
613 cdl.AddRow("PCode", s.PCode);
614 cdl.AddRow("ProfileBegin", s.ProfileBegin);
615 cdl.AddRow("ProfileEnd", s.ProfileEnd);
616 cdl.AddRow("ProfileHollow", s.ProfileHollow);
617 cdl.AddRow("ProfileShape", s.ProfileShape);
618 cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
619 cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
620 cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
621 cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
622 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
623 cdl.AddRow("Rotation (Relative)", sop.RotationOffset);
624 cdl.AddRow("Rotation (World)", sop.GetWorldRotation());
625 cdl.AddRow("Scale", s.Scale);
626 cdl.AddRow(
627 "SculptData",
628 string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
629 cdl.AddRow("SculptEntry", s.SculptEntry);
630 cdl.AddRow("SculptTexture", s.SculptTexture);
631 cdl.AddRow("SculptType", s.SculptType);
632 cdl.AddRow("State", s.State);
633  
634 // TODO, need to display more information about textures but in a compact format
635 // to stop output becoming huge.
636 for (int i = 0; i < sop.GetNumberOfSides(); i++)
637 {
638 Primitive.TextureEntryFace teFace = s.Textures.FaceTextures[i];
639  
640 UUID textureID;
641  
642 if (teFace != null)
643 textureID = teFace.TextureID;
644 else
645 textureID = s.Textures.DefaultTexture.TextureID;
646  
647 cdl.AddRow(string.Format("Face {0} texture ID", i), textureID);
648 }
649  
650 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
651 }
652  
653 object itemsOutput;
654 if (showFull)
655 {
656 StringBuilder itemsSb = new StringBuilder("\n");
657 itemsOutput = AddScenePartItemsReport(itemsSb, sop.Inventory).ToString();
658 }
659 else
660 {
661 itemsOutput = sop.Inventory.Count;
662 }
663  
664 cdl.AddRow("Items", itemsOutput);
665  
666 return sb.Append(cdl.ToString());
667 }
668  
669 private StringBuilder AddScenePartItemsReport(StringBuilder sb, IEntityInventory inv)
670 {
671 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
672 cdt.Indent = 2;
673  
674 cdt.AddColumn("Name", 50);
675 cdt.AddColumn("Type", 12);
676 cdt.AddColumn("Running", 7);
677 cdt.AddColumn("Item UUID", 36);
678 cdt.AddColumn("Asset UUID", 36);
679  
680 foreach (TaskInventoryItem item in inv.GetInventoryItems())
681 {
682 bool foundScriptInstance, scriptRunning;
683 foundScriptInstance
684 = SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, item, out scriptRunning);
685  
686 cdt.AddRow(
687 item.Name,
688 ((InventoryType)item.InvType).ToString(),
689 foundScriptInstance ? scriptRunning.ToString() : "n/a",
690 item.ItemID.ToString(),
691 item.AssetID.ToString());
692 }
693  
694 return sb.Append(cdt.ToString());
695 }
696  
697 private void HandleDeleteObject(string module, string[] cmd)
698 {
699 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
700 return;
701  
702 if (cmd.Length < 3)
703 return;
704  
705 string mode = cmd[2];
706 string o = "";
707  
708 if (mode != "outside")
709 {
710 if (cmd.Length < 4)
711 return;
712  
713 o = cmd[3];
714 }
715  
716 List<SceneObjectGroup> deletes = null;
717 UUID match;
718 bool requireConfirmation = true;
719  
720 switch (mode)
721 {
722 case "owner":
723 if (!UUID.TryParse(o, out match))
724 return;
725  
726 deletes = new List<SceneObjectGroup>();
727  
728 m_scene.ForEachSOG(delegate (SceneObjectGroup g)
729 {
730 if (g.OwnerID == match && !g.IsAttachment)
731 deletes.Add(g);
732 });
733  
734 // if (deletes.Count == 0)
735 // m_console.OutputFormat("No objects were found with owner {0}", match);
736  
737 break;
738  
739 case "creator":
740 if (!UUID.TryParse(o, out match))
741 return;
742  
743 deletes = new List<SceneObjectGroup>();
744  
745 m_scene.ForEachSOG(delegate (SceneObjectGroup g)
746 {
747 if (g.RootPart.CreatorID == match && !g.IsAttachment)
748 deletes.Add(g);
749 });
750  
751 // if (deletes.Count == 0)
752 // m_console.OutputFormat("No objects were found with creator {0}", match);
753  
754 break;
755  
756 case "id":
757 UUID uuid;
758 uint localId;
759 if (!ConsoleUtil.TryParseConsoleId(m_console, o, out uuid, out localId))
760 return;
761  
762 requireConfirmation = false;
763 deletes = new List<SceneObjectGroup>();
764  
765 SceneObjectGroup so;
766 if (localId == ConsoleUtil.LocalIdNotFound)
767 so = m_scene.GetSceneObjectGroup(uuid);
768 else
769 so = m_scene.GetSceneObjectGroup(localId);
770  
771 if (!so.IsAttachment)
772 deletes.Add(so);
773  
774 // if (deletes.Count == 0)
775 // m_console.OutputFormat("No objects were found with uuid {0}", match);
776  
777 break;
778  
779 case "name":
780 deletes = GetDeleteCandidatesByName(module, cmd);
781 break;
782  
783 case "outside":
784 deletes = new List<SceneObjectGroup>();
785  
786 m_scene.ForEachSOG(delegate (SceneObjectGroup g)
787 {
788 SceneObjectPart rootPart = g.RootPart;
789 bool delete = false;
790  
791 if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0)
792 {
793 delete = true;
794 }
795 else
796 {
797 ILandObject parcel
798 = m_scene.LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y);
799  
800 if (parcel == null || parcel.LandData.Name == "NO LAND")
801 delete = true;
802 }
803  
804 if (delete && !g.IsAttachment && !deletes.Contains(g))
805 deletes.Add(g);
806 });
807  
808 if (deletes.Count == 0)
809 m_console.OutputFormat("No objects were found outside region bounds");
810  
811 break;
812  
813 case "pos":
814 deletes = GetDeleteCandidatesByPos(module, cmd);
815 break;
816  
817 default:
818 m_console.OutputFormat("Unrecognized mode {0}", mode);
819 return;
820 }
821  
822 if (deletes == null || deletes.Count <= 0)
823 return;
824  
825 if (requireConfirmation)
826 {
827 string response = MainConsole.Instance.CmdPrompt(
828 string.Format(
829 "Are you sure that you want to delete {0} objects from {1}",
830 deletes.Count, m_scene.RegionInfo.RegionName),
831 "y/N");
832  
833 if (response.ToLower() != "y")
834 {
835 MainConsole.Instance.OutputFormat(
836 "Aborting delete of {0} objects from {1}", deletes.Count, m_scene.RegionInfo.RegionName);
837  
838 return;
839 }
840 }
841  
842 m_console.OutputFormat("Deleting {0} objects in {1}", deletes.Count, m_scene.RegionInfo.RegionName);
843  
844 foreach (SceneObjectGroup g in deletes)
845 {
846 m_console.OutputFormat("Deleting object {0} {1}", g.UUID, g.Name);
847 m_scene.DeleteSceneObject(g, false);
848 }
849 }
850  
851 private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams)
852 {
853 bool useRegex = false;
854 OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
855  
856 List<string> mainParams = options.Parse(cmdparams);
857  
858 if (mainParams.Count < 4)
859 {
860 m_console.OutputFormat("Usage: delete object name [--regex] <name>");
861 return null;
862 }
863  
864 string name = mainParams[3];
865  
866 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
867 Action<SceneObjectGroup> searchAction;
868  
869 if (useRegex)
870 {
871 Regex nameRegex = new Regex(name);
872 searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }};
873 }
874 else
875 {
876 searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }};
877 }
878  
879 m_scene.ForEachSOG(searchAction);
880  
881 if (sceneObjects.Count == 0)
882 m_console.OutputFormat("No objects with name {0} found in {1}", name, m_scene.RegionInfo.RegionName);
883  
884 return sceneObjects;
885 }
886  
887 /// <summary>
888 /// Get scene object delete candidates by position
889 /// </summary>
890 /// <param name='module'></param>
891 /// <param name='cmdparams'></param>
892 /// <returns>null if parsing failed on one of the arguments, otherwise a list of objects to delete. If there
893 /// are no objects to delete then the list will be empty./returns>
894 private List<SceneObjectGroup> GetDeleteCandidatesByPos(string module, string[] cmdparams)
895 {
896 if (cmdparams.Length < 5)
897 {
898 m_console.OutputFormat("Usage: delete object pos <start-coord> to <end-coord>");
899 return null;
900 }
901  
902 Vector3 startVector, endVector;
903  
904 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
905 return null;
906  
907 return m_scene.GetSceneObjectGroups().FindAll(
908 so => !so.IsAttachment && Util.IsInsideBox(so.AbsolutePosition, startVector, endVector));
909 }
910  
911 private bool TryParseVectorRange(IEnumerable<string> rawComponents, out Vector3 startVector, out Vector3 endVector)
912 {
913 string rawConsoleStartVector = rawComponents.Take(1).Single();
914  
915 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
916 {
917 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
918 endVector = Vector3.Zero;
919  
920 return false;
921 }
922  
923 string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single();
924  
925 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
926 {
927 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
928 return false;
929 }
930  
931 return true;
932 }
933 }
934 }