diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index d07cc6a4fb..20ff5b5585 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -72,6 +72,67 @@ namespace OpenSim.Region.Framework.Scenes
{
m_assetService = assetService;
}
+
+ ///
+ /// Gather all the asset uuids associated with the asset referenced by a given uuid
+ ///
+ ///
+ /// This includes both those directly associated with
+ /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
+ /// within this object).
+ /// This method assumes that the asset type associated with this asset in persistent storage is correct (which
+ /// should always be the case). So with this method we always need to retrieve asset data even if the asset
+ /// is of a type which is known not to reference any other assets
+ ///
+ /// The uuid of the asset for which to gather referenced assets
+ /// The assets gathered
+ public void GatherAssetUuids(UUID assetUuid, IDictionary assetUuids)
+ {
+ // avoid infinite loops
+ if (assetUuids.ContainsKey(assetUuid))
+ return;
+
+ try
+ {
+ AssetBase assetBase = GetAsset(assetUuid);
+
+ if (null != assetBase)
+ {
+ sbyte assetType = assetBase.Type;
+ assetUuids[assetUuid] = assetType;
+
+ if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType)
+ {
+ GetWearableAssetUuids(assetBase, assetUuids);
+ }
+ else if ((sbyte)AssetType.Gesture == assetType)
+ {
+ GetGestureAssetUuids(assetBase, assetUuids);
+ }
+ else if ((sbyte)AssetType.Notecard == assetType)
+ {
+ GetTextEmbeddedAssetUuids(assetBase, assetUuids);
+ }
+ else if ((sbyte)AssetType.LSLText == assetType)
+ {
+ GetTextEmbeddedAssetUuids(assetBase, assetUuids);
+ }
+ else if ((sbyte)OpenSimAssetType.Material == assetType)
+ {
+ GetMaterialAssetUuids(assetBase, assetUuids);
+ }
+ else if ((sbyte)AssetType.Object == assetType)
+ {
+ GetSceneObjectAssetUuids(assetBase, assetUuids);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset id {0}", assetUuid);
+ throw;
+ }
+ }
///
/// Gather all the asset uuids associated with the asset referenced by a given uuid
@@ -246,19 +307,6 @@ namespace OpenSim.Region.Framework.Scenes
}
}
-// ///
-// /// The callback made when we request the asset for an object from the asset service.
-// ///
-// private void AssetReceived(string id, Object sender, AssetBase asset)
-// {
-// lock (this)
-// {
-// m_requestedObjectAsset = asset;
-// m_waitingForObjectAsset = false;
-// Monitor.Pulse(this);
-// }
-// }
-
///
/// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps
/// stored in legacy format in part.DynAttrs
@@ -362,32 +410,42 @@ namespace OpenSim.Region.Framework.Scenes
}
///
- /// Record the asset uuids embedded within the given script.
+ /// Record the asset uuids embedded within the given text (e.g. a script).
///
- ///
+ ///
/// Dictionary in which to record the references
- private void GetTextEmbeddedAssetUuids(UUID embeddingAssetId, IDictionary assetUuids)
+ private void GetTextEmbeddedAssetUuids(UUID textAssetUuid, IDictionary assetUuids)
{
// m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId);
- AssetBase embeddingAsset = GetAsset(embeddingAssetId);
+ AssetBase textAsset = GetAsset(textAssetUuid);
- if (null != embeddingAsset)
+ if (null != textAsset)
+ GetTextEmbeddedAssetUuids(textAsset, assetUuids);
+ }
+
+ ///
+ /// Record the asset uuids embedded within the given text (e.g. a script).
+ ///
+ ///
+ /// Dictionary in which to record the references
+ private void GetTextEmbeddedAssetUuids(AssetBase textAsset, IDictionary assetUuids)
+ {
+ // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId);
+
+ string script = Utils.BytesToString(textAsset.Data);
+ // m_log.DebugFormat("[ARCHIVER]: Script {0}", script);
+ MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script);
+ // m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count);
+
+ foreach (Match uuidMatch in uuidMatches)
{
- string script = Utils.BytesToString(embeddingAsset.Data);
-// m_log.DebugFormat("[ARCHIVER]: Script {0}", script);
- MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script);
-// m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count);
+ UUID uuid = new UUID(uuidMatch.Value);
+ // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid);
- foreach (Match uuidMatch in uuidMatches)
- {
- UUID uuid = new UUID(uuidMatch.Value);
-// m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid);
-
- // Embedded asset references (if not false positives) could be for many types of asset, so we will
- // label these as unknown.
- assetUuids[uuid] = (sbyte)AssetType.Unknown;
- }
+ // Embedded asset references (if not false positives) could be for many types of asset, so we will
+ // label these as unknown.
+ assetUuids[uuid] = (sbyte)AssetType.Unknown;
}
}
@@ -401,18 +459,26 @@ namespace OpenSim.Region.Framework.Scenes
AssetBase assetBase = GetAsset(wearableAssetUuid);
if (null != assetBase)
+ GetWearableAssetUuids(assetBase, assetUuids);
+ }
+
+ ///
+ /// Record the uuids referenced by the given wearable asset
+ ///
+ ///
+ /// Dictionary in which to record the references
+ private void GetWearableAssetUuids(AssetBase assetBase, IDictionary assetUuids)
+ {
+ //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data));
+ AssetWearable wearableAsset = new AssetBodypart(assetBase.FullID, assetBase.Data);
+ wearableAsset.Decode();
+
+ //m_log.DebugFormat(
+ // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
+
+ foreach (UUID uuid in wearableAsset.Textures.Values)
{
- //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data));
- AssetWearable wearableAsset = new AssetBodypart(wearableAssetUuid, assetBase.Data);
- wearableAsset.Decode();
-
- //m_log.DebugFormat(
- // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
-
- foreach (UUID uuid in wearableAsset.Textures.Values)
- {
- assetUuids[uuid] = (sbyte)AssetType.Texture;
- }
+ assetUuids[uuid] = (sbyte)AssetType.Texture;
}
}
@@ -425,25 +491,35 @@ namespace OpenSim.Region.Framework.Scenes
///
private void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary assetUuids)
{
- AssetBase objectAsset = GetAsset(sceneObjectUuid);
+ AssetBase sceneObjectAsset = GetAsset(sceneObjectUuid);
- if (null != objectAsset)
+ if (null != sceneObjectAsset)
+ GetSceneObjectAssetUuids(sceneObjectAsset, assetUuids);
+ }
+
+ ///
+ /// Get all the asset uuids associated with a given object. This includes both those directly associated with
+ /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
+ /// within this object).
+ ///
+ ///
+ ///
+ private void GetSceneObjectAssetUuids(AssetBase sceneObjectAsset, IDictionary assetUuids)
+ {
+ string xml = Utils.BytesToString(sceneObjectAsset.Data);
+
+ CoalescedSceneObjects coa;
+ if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa))
{
- string xml = Utils.BytesToString(objectAsset.Data);
-
- CoalescedSceneObjects coa;
- if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa))
- {
- foreach (SceneObjectGroup sog in coa.Objects)
- GatherAssetUuids(sog, assetUuids);
- }
- else
- {
- SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml);
-
- if (null != sog)
- GatherAssetUuids(sog, assetUuids);
- }
+ foreach (SceneObjectGroup sog in coa.Objects)
+ GatherAssetUuids(sog, assetUuids);
+ }
+ else
+ {
+ SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml);
+
+ if (null != sog)
+ GatherAssetUuids(sog, assetUuids);
}
}
@@ -454,12 +530,22 @@ namespace OpenSim.Region.Framework.Scenes
///
private void GetGestureAssetUuids(UUID gestureUuid, IDictionary assetUuids)
{
- AssetBase assetBase = GetAsset(gestureUuid);
- if (null == assetBase)
+ AssetBase gestureAsset = GetAsset(gestureUuid);
+ if (null == gestureAsset)
return;
- using (MemoryStream ms = new MemoryStream(assetBase.Data))
- using (StreamReader sr = new StreamReader(ms))
+ GetGestureAssetUuids(gestureAsset, assetUuids);
+ }
+
+ ///
+ /// Get the asset uuid associated with a gesture
+ ///
+ ///
+ ///
+ private void GetGestureAssetUuids(AssetBase gestureAsset, IDictionary assetUuids)
+ {
+ using (MemoryStream ms = new MemoryStream(gestureAsset.Data))
+ using (StreamReader sr = new StreamReader(ms))
{
sr.ReadLine(); // Unknown (Version?)
sr.ReadLine(); // Unknown
@@ -500,7 +586,15 @@ namespace OpenSim.Region.Framework.Scenes
if (null == assetBase)
return;
- OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(assetBase.Data);
+ GetMaterialAssetUuids(assetBase, assetUuids);
+ }
+
+ ///
+ /// Get the asset uuid's referenced in a material.
+ ///
+ private void GetMaterialAssetUuids(AssetBase materialAsset, IDictionary assetUuids)
+ {
+ OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data);
UUID normMap = mat["NormMap"].AsUUID();
if (normMap != UUID.Zero)
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
index 51dfd47516..f67f6131d4 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
@@ -51,7 +51,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- private Dictionary m_scenes = new Dictionary();
+ private List m_scenes = new List();
+
// private IAvatarFactoryModule m_avatarFactory;
public string Name { get { return "Appearance Information Module"; } }
@@ -83,7 +84,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
lock (m_scenes)
- m_scenes.Remove(scene.RegionInfo.RegionID);
+ m_scenes.Remove(scene);
}
public void RegionLoaded(Scene scene)
@@ -91,7 +92,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
lock (m_scenes)
- m_scenes[scene.RegionInfo.RegionID] = scene;
+ m_scenes.Add(scene);
scene.AddCommand(
"Users", this, "show appearance",
@@ -140,6 +141,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
"If no avatar name is given then a general summary for all avatars in the scene is shown.\n"
+ "If an avatar name is given then specific information about current wearables is shown.",
HandleShowWearablesCommand);
+
+ scene.AddCommand(
+ "Users", this, "wearables check",
+ "wearables check ",
+ "Check that the wearables of a given avatar in the scene are valid.",
+ "This currently checks that the wearable assets themselves and any assets referenced by them exist.",
+ HandleCheckWearablesCommand);
}
private void HandleSendAppearanceCommand(string module, string[] cmd)
@@ -163,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
lock (m_scenes)
{
- foreach (Scene scene in m_scenes.Values)
+ foreach (Scene scene in m_scenes)
{
if (targetNameSupplied)
{
@@ -215,7 +223,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
lock (m_scenes)
{
- foreach (Scene scene in m_scenes.Values)
+ foreach (Scene scene in m_scenes)
{
if (targetNameSupplied)
{
@@ -251,7 +259,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
lock (m_scenes)
{
- foreach (Scene scene in m_scenes.Values)
+ foreach (Scene scene in m_scenes)
{
ScenePresence sp = scene.GetScenePresence(firstname, lastname);
if (sp != null && !sp.IsChildAgent)
@@ -285,7 +293,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
lock (m_scenes)
{
- foreach (Scene scene in m_scenes.Values)
+ foreach (Scene scene in m_scenes)
{
scene.ForEachRootScenePresence(
sp =>
@@ -338,7 +346,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
{
lock (m_scenes)
{
- foreach (Scene scene in m_scenes.Values)
+ foreach (Scene scene in m_scenes)
{
ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
if (sp != null && !sp.IsChildAgent)
@@ -354,7 +362,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
lock (m_scenes)
{
- foreach (Scene scene in m_scenes.Values)
+ foreach (Scene scene in m_scenes)
{
scene.ForEachRootScenePresence(
sp =>
@@ -376,6 +384,76 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
MainConsole.Instance.Output(sb.ToString());
}
+ private void HandleCheckWearablesCommand(string module, string[] cmd)
+ {
+ if (cmd.Length != 4)
+ {
+ MainConsole.Instance.OutputFormat("Usage: wearables check ");
+ return;
+ }
+
+ string firstname = cmd[2];
+ string lastname = cmd[3];
+
+ StringBuilder sb = new StringBuilder();
+ UuidGatherer uuidGatherer = new UuidGatherer(m_scenes[0].AssetService);
+
+ lock (m_scenes)
+ {
+ foreach (Scene scene in m_scenes)
+ {
+ ScenePresence sp = scene.GetScenePresence(firstname, lastname);
+ if (sp != null && !sp.IsChildAgent)
+ {
+ sb.AppendFormat("Wearables checks for {0}\n\n", sp.Name);
+
+ for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++)
+ {
+ AvatarWearable aw = sp.Appearance.Wearables[i];
+
+ if (aw.Count > 0)
+ {
+ sb.Append(Enum.GetName(typeof(WearableType), i));
+ sb.Append("\n");
+
+ for (int j = 0; j < aw.Count; j++)
+ {
+ WearableItem wi = aw[j];
+
+ ConsoleDisplayList cdl = new ConsoleDisplayList();
+ cdl.Indent = 2;
+ cdl.AddRow("Item UUID", wi.ItemID);
+ cdl.AddRow("Assets", "");
+ sb.Append(cdl.ToString());
+
+ Dictionary assetUuids = new Dictionary();
+ uuidGatherer.GatherAssetUuids(wi.AssetID, assetUuids);
+ string[] assetStrings
+ = Array.ConvertAll(assetUuids.Keys.ToArray(), u => u.ToString());
+
+ bool[] existChecks = scene.AssetService.AssetsExist(assetStrings);
+
+ ConsoleDisplayTable cdt = new ConsoleDisplayTable();
+ cdt.Indent = 4;
+ cdt.AddColumn("Type", 10);
+ cdt.AddColumn("UUID", ConsoleDisplayUtil.UuidSize);
+ cdt.AddColumn("Found", 5);
+
+ for (int k = 0; k < existChecks.Length; k++)
+ cdt.AddRow((AssetType)assetUuids[new UUID(assetStrings[k])], assetStrings[k], existChecks[k] ? "yes" : "no");
+
+ sb.Append(cdt.ToString());
+ sb.Append("\n");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ MainConsole.Instance.Output(sb.ToString());
+ }
+
private void AppendWearablesDetailReport(ScenePresence sp, StringBuilder sb)
{
sb.AppendFormat("\nWearables for {0}\n", sp.Name);