diff options
author | UbitUmarov | 2015-09-01 11:43:07 +0100 |
---|---|---|
committer | UbitUmarov | 2015-09-01 11:43:07 +0100 |
commit | fb78b182520fc9bb0f971afd0322029c70278ea6 (patch) | |
tree | b4e30d383938fdeef8c92d1d1c2f44bb61d329bd /OpenSim/Region/OptionalModules/Avatar/Appearance | |
parent | lixo (diff) | |
parent | Mantis #7713: fixed bug introduced by 1st MOSES patch. (diff) | |
download | opensim-SC_OLD-fb78b182520fc9bb0f971afd0322029c70278ea6.zip opensim-SC_OLD-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.gz opensim-SC_OLD-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.bz2 opensim-SC_OLD-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.xz |
Merge remote-tracking branch 'os/master'
Diffstat (limited to 'OpenSim/Region/OptionalModules/Avatar/Appearance')
-rw-r--r-- | OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs new file mode 100644 index 0000000..2f9bb1e --- /dev/null +++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs | |||
@@ -0,0 +1,482 @@ | |||
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.Linq; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | using OpenMetaverse; | ||
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; | ||
43 | |||
44 | namespace OpenSim.Region.OptionalModules.Avatar.Appearance | ||
45 | { | ||
46 | /// <summary> | ||
47 | /// A module that just holds commands for inspecting avatar appearance. | ||
48 | /// </summary> | ||
49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AppearanceInfoModule")] | ||
50 | public class AppearanceInfoModule : ISharedRegionModule | ||
51 | { | ||
52 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | |||
54 | private List<Scene> m_scenes = new List<Scene>(); | ||
55 | |||
56 | // private IAvatarFactoryModule m_avatarFactory; | ||
57 | |||
58 | public string Name { get { return "Appearance Information Module"; } } | ||
59 | |||
60 | public Type ReplaceableInterface { get { return null; } } | ||
61 | |||
62 | public void Initialise(IConfigSource source) | ||
63 | { | ||
64 | // m_log.DebugFormat("[APPEARANCE INFO MODULE]: INITIALIZED MODULE"); | ||
65 | } | ||
66 | |||
67 | public void PostInitialise() | ||
68 | { | ||
69 | // m_log.DebugFormat("[APPEARANCE INFO MODULE]: POST INITIALIZED MODULE"); | ||
70 | } | ||
71 | |||
72 | public void Close() | ||
73 | { | ||
74 | // m_log.DebugFormat("[APPEARANCE INFO MODULE]: CLOSED MODULE"); | ||
75 | } | ||
76 | |||
77 | public void AddRegion(Scene scene) | ||
78 | { | ||
79 | // m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); | ||
80 | } | ||
81 | |||
82 | public void RemoveRegion(Scene scene) | ||
83 | { | ||
84 | // m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); | ||
85 | |||
86 | lock (m_scenes) | ||
87 | m_scenes.Remove(scene); | ||
88 | } | ||
89 | |||
90 | public void RegionLoaded(Scene scene) | ||
91 | { | ||
92 | // m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); | ||
93 | |||
94 | lock (m_scenes) | ||
95 | m_scenes.Add(scene); | ||
96 | |||
97 | scene.AddCommand( | ||
98 | "Users", this, "show appearance", | ||
99 | "show appearance [<first-name> <last-name>]", | ||
100 | "Synonym for 'appearance show'", | ||
101 | HandleShowAppearanceCommand); | ||
102 | |||
103 | scene.AddCommand( | ||
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); | ||
112 | |||
113 | scene.AddCommand( | ||
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); | ||
119 | |||
120 | scene.AddCommand( | ||
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); | ||
129 | |||
130 | scene.AddCommand( | ||
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); | ||
136 | |||
137 | scene.AddCommand( | ||
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); | ||
144 | |||
145 | scene.AddCommand( | ||
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); | ||
151 | } | ||
152 | |||
153 | private void HandleSendAppearanceCommand(string module, string[] cmd) | ||
154 | { | ||
155 | if (cmd.Length != 2 && cmd.Length < 4) | ||
156 | { | ||
157 | MainConsole.Instance.OutputFormat("Usage: appearance send [<first-name> <last-name>]"); | ||
158 | return; | ||
159 | } | ||
160 | |||
161 | bool targetNameSupplied = false; | ||
162 | string optionalTargetFirstName = null; | ||
163 | string optionalTargetLastName = null; | ||
164 | |||
165 | if (cmd.Length >= 4) | ||
166 | { | ||
167 | targetNameSupplied = true; | ||
168 | optionalTargetFirstName = cmd[2]; | ||
169 | optionalTargetLastName = cmd[3]; | ||
170 | } | ||
171 | |||
172 | lock (m_scenes) | ||
173 | { | ||
174 | foreach (Scene scene in m_scenes) | ||
175 | { | ||
176 | if (targetNameSupplied) | ||
177 | { | ||
178 | ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName); | ||
179 | if (sp != null && !sp.IsChildAgent) | ||
180 | { | ||
181 | MainConsole.Instance.OutputFormat( | ||
182 | "Sending appearance information for {0} to all other avatars in {1}", | ||
183 | sp.Name, scene.RegionInfo.RegionName); | ||
184 | |||
185 | scene.AvatarFactory.SendAppearance(sp.UUID); | ||
186 | } | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | scene.ForEachRootScenePresence( | ||
191 | sp => | ||
192 | { | ||
193 | MainConsole.Instance.OutputFormat( | ||
194 | "Sending appearance information for {0} to all other avatars in {1}", | ||
195 | sp.Name, scene.RegionInfo.RegionName); | ||
196 | |||
197 | scene.AvatarFactory.SendAppearance(sp.UUID); | ||
198 | } | ||
199 | ); | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | |||
205 | private void HandleShowAppearanceCommand(string module, string[] cmd) | ||
206 | { | ||
207 | if (cmd.Length != 2 && cmd.Length < 4) | ||
208 | { | ||
209 | MainConsole.Instance.OutputFormat("Usage: appearance show [<first-name> <last-name>]"); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | bool targetNameSupplied = false; | ||
214 | string optionalTargetFirstName = null; | ||
215 | string optionalTargetLastName = null; | ||
216 | |||
217 | if (cmd.Length >= 4) | ||
218 | { | ||
219 | targetNameSupplied = true; | ||
220 | optionalTargetFirstName = cmd[2]; | ||
221 | optionalTargetLastName = cmd[3]; | ||
222 | } | ||
223 | |||
224 | lock (m_scenes) | ||
225 | { | ||
226 | foreach (Scene scene in m_scenes) | ||
227 | { | ||
228 | if (targetNameSupplied) | ||
229 | { | ||
230 | ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName); | ||
231 | if (sp != null && !sp.IsChildAgent) | ||
232 | scene.AvatarFactory.WriteBakedTexturesReport(sp, MainConsole.Instance.OutputFormat); | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | scene.ForEachRootScenePresence( | ||
237 | sp => | ||
238 | { | ||
239 | bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp); | ||
240 | MainConsole.Instance.OutputFormat( | ||
241 | "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete"); | ||
242 | } | ||
243 | ); | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | private void HandleRebakeAppearanceCommand(string module, string[] cmd) | ||
250 | { | ||
251 | if (cmd.Length != 4) | ||
252 | { | ||
253 | MainConsole.Instance.OutputFormat("Usage: appearance rebake <first-name> <last-name>"); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | string firstname = cmd[2]; | ||
258 | string lastname = cmd[3]; | ||
259 | |||
260 | lock (m_scenes) | ||
261 | { | ||
262 | foreach (Scene scene in m_scenes) | ||
263 | { | ||
264 | ScenePresence sp = scene.GetScenePresence(firstname, lastname); | ||
265 | if (sp != null && !sp.IsChildAgent) | ||
266 | { | ||
267 | int rebakesRequested = scene.AvatarFactory.RequestRebake(sp, false); | ||
268 | |||
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); | ||
273 | else | ||
274 | MainConsole.Instance.OutputFormat( | ||
275 | "No texture IDs available for rebake request for {0} in {1}", | ||
276 | sp.Name, scene.RegionInfo.RegionName); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | private void HandleFindAppearanceCommand(string module, string[] cmd) | ||
283 | { | ||
284 | if (cmd.Length != 3) | ||
285 | { | ||
286 | MainConsole.Instance.OutputFormat("Usage: appearance find <uuid-or-start-of-uuid>"); | ||
287 | return; | ||
288 | } | ||
289 | |||
290 | string rawUuid = cmd[2]; | ||
291 | |||
292 | HashSet<ScenePresence> matchedAvatars = new HashSet<ScenePresence>(); | ||
293 | |||
294 | lock (m_scenes) | ||
295 | { | ||
296 | foreach (Scene scene in m_scenes) | ||
297 | { | ||
298 | scene.ForEachRootScenePresence( | ||
299 | sp => | ||
300 | { | ||
301 | Dictionary<BakeType, Primitive.TextureEntryFace> bakedFaces = scene.AvatarFactory.GetBakedTextureFaces(sp.UUID); | ||
302 | foreach (Primitive.TextureEntryFace face in bakedFaces.Values) | ||
303 | { | ||
304 | if (face != null && face.TextureID.ToString().StartsWith(rawUuid)) | ||
305 | matchedAvatars.Add(sp); | ||
306 | } | ||
307 | }); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | if (matchedAvatars.Count == 0) | ||
312 | { | ||
313 | MainConsole.Instance.OutputFormat("{0} did not match any baked avatar textures in use", rawUuid); | ||
314 | } | ||
315 | else | ||
316 | { | ||
317 | MainConsole.Instance.OutputFormat( | ||
318 | "{0} matched {1}", | ||
319 | rawUuid, | ||
320 | string.Join(", ", matchedAvatars.ToList().ConvertAll<string>(sp => sp.Name).ToArray())); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | protected void HandleShowWearablesCommand(string module, string[] cmd) | ||
325 | { | ||
326 | if (cmd.Length != 2 && cmd.Length < 4) | ||
327 | { | ||
328 | MainConsole.Instance.OutputFormat("Usage: wearables show [<first-name> <last-name>]"); | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | bool targetNameSupplied = false; | ||
333 | string optionalTargetFirstName = null; | ||
334 | string optionalTargetLastName = null; | ||
335 | |||
336 | if (cmd.Length >= 4) | ||
337 | { | ||
338 | targetNameSupplied = true; | ||
339 | optionalTargetFirstName = cmd[2]; | ||
340 | optionalTargetLastName = cmd[3]; | ||
341 | } | ||
342 | |||
343 | StringBuilder sb = new StringBuilder(); | ||
344 | |||
345 | if (targetNameSupplied) | ||
346 | { | ||
347 | lock (m_scenes) | ||
348 | { | ||
349 | foreach (Scene scene in m_scenes) | ||
350 | { | ||
351 | ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName); | ||
352 | if (sp != null && !sp.IsChildAgent) | ||
353 | AppendWearablesDetailReport(sp, sb); | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | else | ||
358 | { | ||
359 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
360 | cdt.AddColumn("Name", ConsoleDisplayUtil.UserNameSize); | ||
361 | cdt.AddColumn("Wearables", 2); | ||
362 | |||
363 | lock (m_scenes) | ||
364 | { | ||
365 | foreach (Scene scene in m_scenes) | ||
366 | { | ||
367 | scene.ForEachRootScenePresence( | ||
368 | sp => | ||
369 | { | ||
370 | int count = 0; | ||
371 | |||
372 | for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++) | ||
373 | count += sp.Appearance.Wearables[i].Count; | ||
374 | |||
375 | cdt.AddRow(sp.Name, count); | ||
376 | } | ||
377 | ); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | sb.Append(cdt.ToString()); | ||
382 | } | ||
383 | |||
384 | MainConsole.Instance.Output(sb.ToString()); | ||
385 | } | ||
386 | |||
387 | private void HandleCheckWearablesCommand(string module, string[] cmd) | ||
388 | { | ||
389 | if (cmd.Length != 4) | ||
390 | { | ||
391 | MainConsole.Instance.OutputFormat("Usage: wearables check <first-name> <last-name>"); | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | string firstname = cmd[2]; | ||
396 | string lastname = cmd[3]; | ||
397 | |||
398 | StringBuilder sb = new StringBuilder(); | ||
399 | UuidGatherer uuidGatherer = new UuidGatherer(m_scenes[0].AssetService); | ||
400 | |||
401 | lock (m_scenes) | ||
402 | { | ||
403 | foreach (Scene scene in m_scenes) | ||
404 | { | ||
405 | ScenePresence sp = scene.GetScenePresence(firstname, lastname); | ||
406 | if (sp != null && !sp.IsChildAgent) | ||
407 | { | ||
408 | sb.AppendFormat("Wearables checks for {0}\n\n", sp.Name); | ||
409 | |||
410 | for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++) | ||
411 | { | ||
412 | AvatarWearable aw = sp.Appearance.Wearables[i]; | ||
413 | |||
414 | if (aw.Count > 0) | ||
415 | { | ||
416 | sb.Append(Enum.GetName(typeof(WearableType), i)); | ||
417 | sb.Append("\n"); | ||
418 | |||
419 | for (int j = 0; j < aw.Count; j++) | ||
420 | { | ||
421 | WearableItem wi = aw[j]; | ||
422 | |||
423 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | ||
424 | cdl.Indent = 2; | ||
425 | cdl.AddRow("Item UUID", wi.ItemID); | ||
426 | cdl.AddRow("Assets", ""); | ||
427 | sb.Append(cdl.ToString()); | ||
428 | |||
429 | uuidGatherer.AddForInspection(wi.AssetID); | ||
430 | uuidGatherer.GatherAll(); | ||
431 | string[] assetStrings | ||
432 | = Array.ConvertAll<UUID, string>(uuidGatherer.GatheredUuids.Keys.ToArray(), u => u.ToString()); | ||
433 | |||
434 | bool[] existChecks = scene.AssetService.AssetsExist(assetStrings); | ||
435 | |||
436 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
437 | cdt.Indent = 4; | ||
438 | cdt.AddColumn("Type", 10); | ||
439 | cdt.AddColumn("UUID", ConsoleDisplayUtil.UuidSize); | ||
440 | cdt.AddColumn("Found", 5); | ||
441 | |||
442 | for (int k = 0; k < existChecks.Length; k++) | ||
443 | cdt.AddRow( | ||
444 | (AssetType)uuidGatherer.GatheredUuids[new UUID(assetStrings[k])], | ||
445 | assetStrings[k], existChecks[k] ? "yes" : "no"); | ||
446 | |||
447 | sb.Append(cdt.ToString()); | ||
448 | sb.Append("\n"); | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
456 | MainConsole.Instance.Output(sb.ToString()); | ||
457 | } | ||
458 | |||
459 | private void AppendWearablesDetailReport(ScenePresence sp, StringBuilder sb) | ||
460 | { | ||
461 | sb.AppendFormat("\nWearables for {0}\n", sp.Name); | ||
462 | |||
463 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
464 | cdt.AddColumn("Type", 10); | ||
465 | cdt.AddColumn("Item UUID", ConsoleDisplayUtil.UuidSize); | ||
466 | cdt.AddColumn("Asset UUID", ConsoleDisplayUtil.UuidSize); | ||
467 | |||
468 | for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++) | ||
469 | { | ||
470 | AvatarWearable aw = sp.Appearance.Wearables[i]; | ||
471 | |||
472 | for (int j = 0; j < aw.Count; j++) | ||
473 | { | ||
474 | WearableItem wi = aw[j]; | ||
475 | cdt.AddRow(Enum.GetName(typeof(WearableType), i), wi.ItemID, wi.AssetID); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | sb.Append(cdt.ToString()); | ||
480 | } | ||
481 | } | ||
482 | } \ No newline at end of file | ||