29 using System.Collections.Generic;
32 using System.Reflection;
34 using System.Text.RegularExpressions;
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;
53 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"ObjectCommandsModule")]
58 private Scene m_scene;
61 public string Name {
get {
return "Object Commands Module"; } }
63 public Type ReplaceableInterface {
get {
return null; } }
85 m_console = MainConsole.Instance;
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.",
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.",
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",
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",
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.",
122 m_console.Commands.AddCommand(
126 "delete object pos <start-coord> to <end-coord>",
127 "Delete scene objects within the given area.",
128 ConsoleUtil.CoordHelp,
131 m_console.Commands.AddCommand(
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);
141 m_console.Commands.AddCommand(
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);
152 m_console.Commands.AddCommand(
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);
163 m_console.Commands.AddCommand(
167 "show part id <UUID-or-localID>",
168 "Show details of a scene object part with the given UUID or localID", HandleShowPartById);
170 m_console.Commands.AddCommand(
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);
179 m_console.Commands.AddCommand(
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);
188 m_console.Commands.AddCommand(
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);
215 private void OutputSogsToConsole(Predicate<SceneObjectGroup> searchPredicate,
bool showFull)
217 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups().FindAll(searchPredicate);
219 StringBuilder sb =
new StringBuilder();
223 AddSceneObjectReport(sb, so, showFull);
227 sb.AppendFormat(
"{0} object(s) found in {1}\n", sceneObjects.Count, m_scene.Name);
229 m_console.OutputFormat(sb.ToString());
232 private void OutputSopsToConsole(Predicate<SceneObjectPart> searchPredicate,
bool showFull)
234 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups();
235 List<SceneObjectPart> parts =
new List<SceneObjectPart>();
237 sceneObjects.ForEach(so => parts.AddRange(Array.FindAll<
SceneObjectPart>(so.Parts, searchPredicate)));
239 StringBuilder sb =
new StringBuilder();
243 AddScenePartReport(sb, part, showFull);
247 sb.AppendFormat(
"{0} parts found in {1}\n", parts.Count, m_scene.Name);
249 m_console.OutputFormat(sb.ToString());
252 private void HandleShowObjectById(
string module,
string[] cmdparams)
254 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
257 bool showFull =
false;
258 OptionSet
options =
new OptionSet().Add(
"full", v => showFull = v != null );
260 List<string> mainParams = options.Parse(cmdparams);
262 if (mainParams.Count < 4)
264 m_console.OutputFormat(
"Usage: show object uuid <uuid>");
276 so = m_scene.GetSceneObjectGroup(localId);
278 so = m_scene.GetSceneObjectGroup(uuid);
286 StringBuilder sb =
new StringBuilder();
287 AddSceneObjectReport(sb, so, showFull);
289 m_console.OutputFormat(sb.ToString());
292 private void HandleShowObjectByName(
string module,
string[] cmdparams)
294 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
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 );
303 List<string> mainParams = options.Parse(cmdparams);
305 if (mainParams.Count < 4)
307 m_console.OutputFormat(
"Usage: show object name [--full] [--regex] <name>");
311 string name = mainParams[3];
313 Predicate<SceneObjectGroup> searchPredicate;
317 Regex nameRegex =
new Regex(name);
318 searchPredicate = so => nameRegex.IsMatch(so.Name);
322 searchPredicate = so => so.Name == name;
325 OutputSogsToConsole(searchPredicate, showFull);
328 private void HandleShowObjectByPos(
string module,
string[] cmdparams)
330 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
333 bool showFull =
false;
334 OptionSet options =
new OptionSet().Add(
"full", v => showFull = v != null );
336 List<string> mainParams = options.Parse(cmdparams);
338 if (mainParams.Count < 5)
340 m_console.OutputFormat(
"Usage: show object pos [--full] <start-coord> to <end-coord>");
344 Vector3 startVector, endVector;
346 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
349 Predicate<SceneObjectGroup> searchPredicate
350 = so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector);
352 OutputSogsToConsole(searchPredicate, showFull);
355 private void HandleShowPartById(
string module,
string[] cmdparams)
357 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
361 OptionSet options =
new OptionSet();
364 List<string> mainParams = options.Parse(cmdparams);
366 if (mainParams.Count < 4)
369 m_console.OutputFormat(
"Usage: show part id <UUID-or-localID>");
380 sop = m_scene.GetSceneObjectPart(objectUuid);
382 sop = m_scene.GetSceneObjectPart(localId);
390 StringBuilder sb =
new StringBuilder();
391 AddScenePartReport(sb, sop,
true);
393 m_console.OutputFormat(sb.ToString());
396 private void HandleShowPartByPos(
string module,
string[] cmdparams)
398 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
402 OptionSet options =
new OptionSet();
405 List<string> mainParams = options.Parse(cmdparams);
407 if (mainParams.Count < 5)
410 m_console.OutputFormat(
"Usage: show part pos [--full] <start-coord> to <end-coord>");
414 string rawConsoleStartVector = mainParams[3];
419 m_console.OutputFormat(
"Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
423 string rawConsoleEndVector = mainParams[5];
428 m_console.OutputFormat(
"Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
432 OutputSopsToConsole(sop => Util.IsInsideBox(sop.
AbsolutePosition, startVector, endVector),
true);
435 private void HandleShowPartByName(
string module,
string[] cmdparams)
437 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
441 bool useRegex =
false;
442 OptionSet options =
new OptionSet();
444 options.Add(
"regex", v => useRegex = v != null );
446 List<string> mainParams = options.Parse(cmdparams);
448 if (mainParams.Count < 4)
450 m_console.OutputFormat(
"Usage: show part name [--regex] <name>");
455 string name = mainParams[3];
457 Predicate<SceneObjectPart> searchPredicate;
461 Regex nameRegex =
new Regex(name);
462 searchPredicate = sop => nameRegex.IsMatch(sop.Name);
466 searchPredicate = sop => sop.Name == name;
469 OutputSopsToConsole(searchPredicate,
true);
472 private void HandleDumpObjectById(
string module,
string[] cmdparams)
474 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
477 if (cmdparams.Length < 4)
479 m_console.OutputFormat(
"Usage: dump object id <UUID-or-localID>");
490 so = m_scene.GetSceneObjectGroup(objectUuid);
492 so = m_scene.GetSceneObjectGroup(localId);
501 objectUuid = so.UUID;
503 string fileName = string.Format(
"{0}.xml", objectUuid);
508 using (XmlTextWriter xtw =
new XmlTextWriter(fileName, Encoding.UTF8))
510 xtw.Formatting = Formatting.Indented;
511 SceneObjectSerializer.ToOriginalXmlFormat(so, xtw,
true);
514 m_console.OutputFormat(
"Object dumped to file {0}", fileName);
527 private StringBuilder AddSceneObjectReport(StringBuilder sb,
SceneObjectGroup so,
bool showFull)
533 AddScenePartReport(sb, sop,
false);
539 AddSummarySceneObjectReport(sb, so);
545 private StringBuilder AddSummarySceneObjectReport(StringBuilder sb,
SceneObjectGroup so)
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);
556 return sb.Append(cdl.ToString());
569 private StringBuilder AddScenePartReport(StringBuilder sb,
SceneObjectPart sop,
bool showFull)
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));
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);
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);
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);
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);
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);
632 cdl.AddRow(
"State", s.State);
636 for (
int i = 0; i < sop.GetNumberOfSides(); i++)
638 Primitive.TextureEntryFace teFace = s.Textures.FaceTextures[i];
643 textureID = teFace.TextureID;
645 textureID = s.Textures.DefaultTexture.TextureID;
647 cdl.AddRow(string.Format(
"Face {0} texture ID", i), textureID);
656 StringBuilder itemsSb =
new StringBuilder(
"\n");
657 itemsOutput = AddScenePartItemsReport(itemsSb, sop.
Inventory).ToString();
661 itemsOutput = sop.Inventory.Count;
664 cdl.AddRow(
"Items", itemsOutput);
666 return sb.Append(cdl.ToString());
669 private StringBuilder AddScenePartItemsReport(StringBuilder sb,
IEntityInventory inv)
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);
682 bool foundScriptInstance, scriptRunning;
684 = SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, item, out scriptRunning);
688 ((InventoryType)item.InvType).ToString(),
689 foundScriptInstance ? scriptRunning.ToString() :
"n/a",
690 item.ItemID.ToString(),
691 item.AssetID.ToString());
694 return sb.Append(cdt.ToString());
697 private void HandleDeleteObject(
string module,
string[] cmd)
699 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
705 string mode = cmd[2];
708 if (mode !=
"outside")
716 List<SceneObjectGroup> deletes = null;
718 bool requireConfirmation =
true;
723 if (!
UUID.TryParse(o, out match))
726 deletes =
new List<SceneObjectGroup>();
740 if (!
UUID.TryParse(o, out match))
743 deletes =
new List<SceneObjectGroup>();
762 requireConfirmation =
false;
763 deletes =
new List<SceneObjectGroup>();
767 so = m_scene.GetSceneObjectGroup(uuid);
769 so = m_scene.GetSceneObjectGroup(localId);
771 if (!so.IsAttachment)
780 deletes = GetDeleteCandidatesByName(module, cmd);
784 deletes =
new List<SceneObjectGroup>();
798 = m_scene.LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y);
800 if (parcel == null || parcel.
LandData.
Name ==
"NO LAND")
808 if (deletes.Count == 0)
809 m_console.OutputFormat(
"No objects were found outside region bounds");
814 deletes = GetDeleteCandidatesByPos(module, cmd);
818 m_console.OutputFormat(
"Unrecognized mode {0}", mode);
822 if (deletes == null || deletes.Count <= 0)
825 if (requireConfirmation)
827 string response = MainConsole.Instance.CmdPrompt(
829 "Are you sure that you want to delete {0} objects from {1}",
830 deletes.Count, m_scene.RegionInfo.RegionName),
833 if (response.ToLower() !=
"y")
835 MainConsole.Instance.OutputFormat(
836 "Aborting delete of {0} objects from {1}", deletes.Count, m_scene.RegionInfo.RegionName);
842 m_console.OutputFormat(
"Deleting {0} objects in {1}", deletes.Count, m_scene.RegionInfo.RegionName);
846 m_console.OutputFormat(
"Deleting object {0} {1}", g.UUID, g.Name);
847 m_scene.DeleteSceneObject(g,
false);
851 private List<SceneObjectGroup> GetDeleteCandidatesByName(
string module,
string[] cmdparams)
853 bool useRegex =
false;
854 OptionSet options =
new OptionSet().Add(
"regex", v=> useRegex = v != null );
856 List<string> mainParams = options.Parse(cmdparams);
858 if (mainParams.Count < 4)
860 m_console.OutputFormat(
"Usage: delete object name [--regex] <name>");
864 string name = mainParams[3];
866 List<SceneObjectGroup> sceneObjects =
new List<SceneObjectGroup>();
867 Action<SceneObjectGroup> searchAction;
871 Regex nameRegex =
new Regex(name);
872 searchAction = so => {
if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }};
876 searchAction = so => {
if (so.Name == name) { sceneObjects.Add(so); }};
879 m_scene.ForEachSOG(searchAction);
881 if (sceneObjects.Count == 0)
882 m_console.OutputFormat(
"No objects with name {0} found in {1}", name, m_scene.RegionInfo.RegionName);
894 private List<SceneObjectGroup> GetDeleteCandidatesByPos(
string module,
string[] cmdparams)
896 if (cmdparams.Length < 5)
898 m_console.OutputFormat(
"Usage: delete object pos <start-coord> to <end-coord>");
902 Vector3 startVector, endVector;
904 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
907 return m_scene.GetSceneObjectGroups().FindAll(
908 so => !so.IsAttachment && Util.IsInsideBox(so.AbsolutePosition, startVector, endVector));
911 private bool TryParseVectorRange(
IEnumerable<string> rawComponents, out Vector3 startVector, out Vector3 endVector)
913 string rawConsoleStartVector = rawComponents.Take(1).Single();
917 m_console.OutputFormat(
"Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
918 endVector = Vector3.Zero;
923 string rawConsoleEndVector = rawComponents.Skip(2).
Take(1).Single();
927 m_console.OutputFormat(
"Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
Used to generated a formatted table for the console.
static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
Convert a maximum vector input from the console to an OpenMetaverse.Vector3
static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
Convert a minimum vector input from the console to an OpenMetaverse.Vector3
Vector3 GroupPosition
The position of the entire group that this prim belongs to.
IEntityInventory Inventory
This part's inventory
Used to generated a formatted table for the console.
static bool TryParseConsoleId(ICommandConsole console, string rawId, out UUID uuid, out uint localId)
Tries to parse the input as either a UUID or a local ID.
A module that holds commands for manipulating objects in the scene.
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
Represents an item in a task inventory
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
List< TaskInventoryItem > GetInventoryItems()
Get all inventory items.
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
const int LocalIdNotFound
OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType SculptType
System.Collections.IEnumerable IEnumerable
Interactive OpenSim region server
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Interface to an entity's (SceneObjectPart's) inventory
static bool CheckFileDoesNotExist(ICommandConsole console, string path)
Check if the given file path exists.
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
bool IsAttachment
Is this scene object acting as an attachment?