29 using System.Collections.Generic;
31 using System.Reflection;
37 using OpenSim.Framework;
38 using OpenSim.Framework.Console;
39 using OpenSim.Framework.Monitoring;
40 using OpenSim.Region.ClientStack.LindenUDP;
41 using OpenSim.Region.Framework.Interfaces;
42 using OpenSim.Region.Framework.Scenes;
49 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"AppearanceInfoModule")]
54 private List<Scene> m_scenes =
new List<Scene>();
58 public string Name {
get {
return "Appearance Information Module"; } }
60 public Type ReplaceableInterface {
get {
return null; } }
87 m_scenes.Remove(scene);
98 "Users",
this,
"show appearance",
99 "show appearance [<first-name> <last-name>]",
100 "Synonym for 'appearance show'",
101 HandleShowAppearanceCommand);
104 "Users",
this,
"appearance show",
105 "appearance show [<first-name> <last-name>]",
106 "Show appearance information for avatars.",
107 "This command checks whether the simulator has all the baked textures required to display an avatar to other viewers. "
108 +
"\nIf not, then appearance is 'corrupt' and other avatars will continue to see it as a cloud."
109 +
"\nOptionally, you can view just a particular avatar's appearance information."
110 +
"\nIn this case, the texture UUID for each bake type is also shown and whether the simulator can find the referenced texture.",
111 HandleShowAppearanceCommand);
114 "Users",
this,
"appearance send",
115 "appearance send [<first-name> <last-name>]",
116 "Send appearance data for each avatar in the simulator to other viewers.",
117 "Optionally, you can specify that only a particular avatar's appearance data is sent.",
118 HandleSendAppearanceCommand);
121 "Users",
this,
"appearance rebake",
122 "appearance rebake <first-name> <last-name>",
123 "Send a request to the user's viewer for it to rebake and reupload its appearance textures.",
124 "This is currently done for all baked texture references previously received, whether the simulator can find the asset or not."
125 +
"\nThis will only work for texture ids that the viewer has already uploaded."
126 +
"\nIf the viewer has not yet sent the server any texture ids then nothing will happen"
127 +
"\nsince requests can only be made for ids that the client has already sent us",
128 HandleRebakeAppearanceCommand);
131 "Users",
this,
"appearance find",
132 "appearance find <uuid-or-start-of-uuid>",
133 "Find out which avatar uses the given asset as a baked texture, if any.",
134 "You can specify just the beginning of the uuid, e.g. 2008a8d. A longer UUID must be in dashed format.",
135 HandleFindAppearanceCommand);
138 "Users",
this,
"wearables show",
139 "wearables show [<first-name> <last-name>]",
140 "Show information about wearables for avatars.",
141 "If no avatar name is given then a general summary for all avatars in the scene is shown.\n"
142 +
"If an avatar name is given then specific information about current wearables is shown.",
143 HandleShowWearablesCommand);
146 "Users",
this,
"wearables check",
147 "wearables check <first-name> <last-name>",
148 "Check that the wearables of a given avatar in the scene are valid.",
149 "This currently checks that the wearable assets themselves and any assets referenced by them exist.",
150 HandleCheckWearablesCommand);
153 private void HandleSendAppearanceCommand(
string module,
string[] cmd)
155 if (cmd.Length != 2 && cmd.Length < 4)
157 MainConsole.Instance.OutputFormat(
"Usage: appearance send [<first-name> <last-name>]");
161 bool targetNameSupplied =
false;
162 string optionalTargetFirstName = null;
163 string optionalTargetLastName = null;
167 targetNameSupplied =
true;
168 optionalTargetFirstName = cmd[2];
169 optionalTargetLastName = cmd[3];
174 foreach (
Scene scene
in m_scenes)
176 if (targetNameSupplied)
178 ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
181 MainConsole.Instance.OutputFormat(
182 "Sending appearance information for {0} to all other avatars in {1}",
183 sp.Name, scene.RegionInfo.RegionName);
185 scene.AvatarFactory.SendAppearance(sp.UUID);
190 scene.ForEachRootScenePresence(
193 MainConsole.Instance.OutputFormat(
194 "Sending appearance information for {0} to all other avatars in {1}",
195 sp.Name, scene.RegionInfo.RegionName);
197 scene.AvatarFactory.SendAppearance(sp.UUID);
205 private void HandleShowAppearanceCommand(
string module,
string[] cmd)
207 if (cmd.Length != 2 && cmd.Length < 4)
209 MainConsole.Instance.OutputFormat(
"Usage: appearance show [<first-name> <last-name>]");
213 bool targetNameSupplied =
false;
214 string optionalTargetFirstName = null;
215 string optionalTargetLastName = null;
219 targetNameSupplied =
true;
220 optionalTargetFirstName = cmd[2];
221 optionalTargetLastName = cmd[3];
226 foreach (
Scene scene
in m_scenes)
228 if (targetNameSupplied)
230 ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
232 scene.AvatarFactory.WriteBakedTexturesReport(sp, MainConsole.Instance.OutputFormat);
236 scene.ForEachRootScenePresence(
239 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp);
240 MainConsole.Instance.OutputFormat(
241 "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ?
"OK" :
"incomplete");
249 private void HandleRebakeAppearanceCommand(
string module,
string[] cmd)
253 MainConsole.Instance.OutputFormat(
"Usage: appearance rebake <first-name> <last-name>");
257 string firstname = cmd[2];
258 string lastname = cmd[3];
262 foreach (
Scene scene
in m_scenes)
264 ScenePresence sp = scene.GetScenePresence(firstname, lastname);
267 int rebakesRequested = scene.AvatarFactory.RequestRebake(sp,
false);
269 if (rebakesRequested > 0)
270 MainConsole.Instance.OutputFormat(
271 "Requesting rebake of {0} uploaded textures for {1} in {2}",
272 rebakesRequested, sp.Name, scene.RegionInfo.RegionName);
274 MainConsole.Instance.OutputFormat(
275 "No texture IDs available for rebake request for {0} in {1}",
276 sp.Name, scene.RegionInfo.RegionName);
282 private void HandleFindAppearanceCommand(
string module,
string[] cmd)
286 MainConsole.Instance.OutputFormat(
"Usage: appearance find <uuid-or-start-of-uuid>");
290 string rawUuid = cmd[2];
292 HashSet<ScenePresence> matchedAvatars =
new HashSet<ScenePresence>();
296 foreach (
Scene scene
in m_scenes)
298 scene.ForEachRootScenePresence(
301 Dictionary<BakeType, Primitive.TextureEntryFace> bakedFaces = scene.AvatarFactory.GetBakedTextureFaces(sp.UUID);
302 foreach (
Primitive.TextureEntryFace face in bakedFaces.Values)
304 if (face != null && face.TextureID.ToString().StartsWith(rawUuid))
305 matchedAvatars.Add(sp);
311 if (matchedAvatars.Count == 0)
313 MainConsole.Instance.OutputFormat(
"{0} did not match any baked avatar textures in use", rawUuid);
317 MainConsole.Instance.OutputFormat(
320 string.Join(
", ", matchedAvatars.ToList().ConvertAll<string>(sp => sp.Name).ToArray()));
326 if (cmd.Length != 2 && cmd.Length < 4)
328 MainConsole.Instance.OutputFormat(
"Usage: wearables show [<first-name> <last-name>]");
332 bool targetNameSupplied =
false;
333 string optionalTargetFirstName = null;
334 string optionalTargetLastName = null;
338 targetNameSupplied =
true;
339 optionalTargetFirstName = cmd[2];
340 optionalTargetLastName = cmd[3];
343 StringBuilder sb =
new StringBuilder();
345 if (targetNameSupplied)
349 foreach (
Scene scene
in m_scenes)
351 ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
353 AppendWearablesDetailReport(sp, sb);
360 cdt.AddColumn(
"Name", ConsoleDisplayUtil.UserNameSize);
361 cdt.AddColumn(
"Wearables", 2);
365 foreach (
Scene scene
in m_scenes)
367 scene.ForEachRootScenePresence(
372 for (
int i = (
int)WearableType.Shape; i < (
int)WearableType.Physics; i++)
373 count += sp.Appearance.Wearables[i].Count;
375 cdt.AddRow(sp.Name, count);
381 sb.Append(cdt.ToString());
384 MainConsole.Instance.Output(sb.ToString());
387 private void HandleCheckWearablesCommand(
string module,
string[] cmd)
391 MainConsole.Instance.OutputFormat(
"Usage: wearables check <first-name> <last-name>");
395 string firstname = cmd[2];
396 string lastname = cmd[3];
398 StringBuilder sb =
new StringBuilder();
403 foreach (
Scene scene
in m_scenes)
405 ScenePresence sp = scene.GetScenePresence(firstname, lastname);
408 sb.AppendFormat(
"Wearables checks for {0}\n\n", sp.Name);
410 for (
int i = (
int)WearableType.Shape; i < (int)WearableType.Physics; i++)
416 sb.Append(Enum.GetName(typeof(WearableType), i));
419 for (
int j = 0; j < aw.Count; j++)
425 cdl.AddRow(
"Item UUID", wi.ItemID);
426 cdl.AddRow(
"Assets",
"");
427 sb.Append(cdl.ToString());
429 uuidGatherer.AddForInspection(wi.AssetID);
430 uuidGatherer.GatherAll();
431 string[] assetStrings
432 = Array.ConvertAll<
UUID,
string>(uuidGatherer.GatheredUuids.Keys.ToArray(), u => u.ToString());
434 bool[] existChecks = scene.AssetService.AssetsExist(assetStrings);
438 cdt.AddColumn(
"Type", 10);
439 cdt.AddColumn(
"UUID", ConsoleDisplayUtil.UuidSize);
440 cdt.AddColumn(
"Found", 5);
442 for (
int k = 0; k < existChecks.Length; k++)
444 (AssetType)uuidGatherer.
GatheredUuids[
new UUID(assetStrings[k])],
445 assetStrings[k], existChecks[k] ?
"yes" :
"no");
447 sb.Append(cdt.ToString());
456 MainConsole.Instance.Output(sb.ToString());
459 private void AppendWearablesDetailReport(
ScenePresence sp, StringBuilder sb)
461 sb.AppendFormat(
"\nWearables for {0}\n", sp.Name);
464 cdt.AddColumn(
"Type", 10);
465 cdt.AddColumn(
"Item UUID", ConsoleDisplayUtil.UuidSize);
466 cdt.AddColumn(
"Asset UUID", ConsoleDisplayUtil.UuidSize);
468 for (
int i = (
int)WearableType.Shape; i < (int)WearableType.Physics; i++)
472 for (
int j = 0; j < aw.Count; j++)
475 cdt.AddRow(Enum.GetName(typeof(WearableType), i), wi.
ItemID, wi.
AssetID);
479 sb.Append(cdt.ToString());
Used to generated a formatted table for the console.
Gather uuids for a given entity.
Used to generated a formatted table for the console.
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
A module that just holds commands for inspecting avatar appearance.
IDictionary< UUID, sbyte > GatheredUuids
The dictionary of UUIDs gathered so far. If Complete == true then this is all the reachable UUIDs...
Interactive OpenSim region server
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void HandleShowWearablesCommand(string module, string[] cmd)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...