29 using System.Collections.Generic;
31 using System.Reflection;
32 using System.Security.Cryptography;
38 using OpenMetaverse.StructuredData;
40 using OpenSim.Framework;
41 using OpenSim.Framework.Servers;
42 using OpenSim.Framework.Servers.HttpServer;
43 using OpenSim.Region.Framework.Interfaces;
44 using OpenSim.Region.Framework.Scenes;
57 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"MaterialsModule")]
60 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 public string Name {
get {
return "MaterialsModule"; } }
64 public Type ReplaceableInterface {
get {
return null; } }
66 private Scene m_scene = null;
67 private bool m_enabled =
false;
68 private int m_maxMaterialsPerTransaction = 50;
70 public Dictionary<UUID, OSDMap> m_regionMaterials =
new Dictionary<UUID, OSDMap>();
76 IConfig config = source.Configs[
"Materials"];
79 m_enabled = config.GetBoolean(
"enable_materials", m_enabled);
80 m_maxMaterialsPerTransaction = config.GetInt(
"MaxMaterialsPerTransaction", m_maxMaterialsPerTransaction);
84 m_log.DebugFormat(
"[Materials]: Initialized");
99 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
100 m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
105 foreach (var part
in obj.
Parts)
107 GetStoredMaterialsInPart(part);
110 private void OnRegisterCaps(OpenMetaverse.UUID agentID,
OpenSim.Framework.Capabilities.Caps caps)
112 string capsBase =
"/CAPS/" + caps.CapsObjectPath;
116 (request, path, param, httpRequest, httpResponse)
117 => RenderMaterialsPostCap(request, agentID),
118 "RenderMaterials", null);
119 caps.RegisterHandler(
"RenderMaterials", renderMaterialsPostHandler);
127 (request, path, param, httpRequest, httpResponse)
128 => RenderMaterialsGetCap(request),
129 "RenderMaterials", null);
130 MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler);
135 (request, path, param, httpRequest, httpResponse)
136 => RenderMaterialsPostCap(request, agentID),
137 "RenderMaterials", null);
138 MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler);
146 m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
147 m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
152 if (!m_enabled)
return;
155 if (featuresModule != null)
156 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
159 private void OnSimulatorFeaturesRequest(UUID agentID, ref
OSDMap features)
161 features[
"MaxMaterialsPerTransaction"] = m_maxMaterialsPerTransaction;
173 OSD OSMaterials = null;
180 OSDMap materialsStore = part.DynAttrs.GetStore(
"OpenSim",
"Materials");
182 if (materialsStore == null)
185 materialsStore.TryGetValue(
"Materials", out OSMaterials);
188 if (OSMaterials != null && OSMaterials is
OSDArray)
197 foreach (
OSD elemOsd
in matsArr)
199 if (elemOsd != null && elemOsd is
OSDMap)
201 OSDMap matMap = elemOsd as
OSDMap;
202 if (matMap.ContainsKey(
"ID") && matMap.ContainsKey(
"Material"))
206 lock (m_regionMaterials)
207 m_regionMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["
Material"];
211 m_log.Warn(
"[Materials]: exception decoding persisted legacy material: " + e.ToString());
223 if (part.
Shape == null)
226 var te =
new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length);
230 GetLegacyStoredMaterialsInPart(part);
232 if (te.DefaultTexture != null)
233 GetStoredMaterialInFace(part, te.DefaultTexture);
236 "[Materials]: Default texture for part {0} (part of object {1}) in {2} unexpectedly null. Ignoring.",
237 part.Name, part.ParentGroup.Name, m_scene.Name);
239 foreach (
Primitive.TextureEntryFace face in te.FaceTextures)
242 GetStoredMaterialInFace(part, face);
251 UUID id = face.MaterialID;
255 lock (m_regionMaterials)
257 if (m_regionMaterials.ContainsKey(
id))
260 byte[] data = m_scene.AssetService.GetData(id.ToString());
263 m_log.WarnFormat(
"[Materials]: Prim \"{0}\" ({1}) contains unknown material ID {2}", part.Name, part.UUID, id);
270 mat = (
OSDMap)OSDParser.DeserializeLLSDXml(data);
274 m_log.WarnFormat(
"[Materials]: cannot decode material asset {0}: {1}", id, e.Message);
278 m_regionMaterials[id] = mat;
284 OSDMap req = (
OSDMap)OSDParser.DeserializeLLSDXml(request);
287 OSDMap materialsFromViewer = null;
291 if (req.ContainsKey(
"Zipped"))
295 byte[] inBytes = req[
"Zipped"].AsBinary();
299 osd = ZDecompressBytesToOsd(inBytes);
305 foreach (
OSD elem
in (OSDArray)osd)
309 UUID id =
new UUID(elem.AsBinary(), 0);
311 lock (m_regionMaterials)
313 if (m_regionMaterials.ContainsKey(
id))
316 matMap[
"ID"] = OSD.FromBinary(id.GetBytes());
317 matMap[
"Material"] = m_regionMaterials[id];
322 m_log.Warn(
"[Materials]: request for unknown material ID: " + id.ToString());
333 m_log.Error(
"Error getting materials in response to viewer request", e);
340 materialsFromViewer = osd as
OSDMap;
342 if (materialsFromViewer.ContainsKey(
"FullMaterialsPerFace"))
344 OSD matsOsd = materialsFromViewer[
"FullMaterialsPerFace"];
345 if (matsOsd is OSDArray)
347 OSDArray matsArr = matsOsd as
OSDArray;
351 foreach (OSDMap matsMap
in matsArr)
353 uint primLocalID = 0;
355 primLocalID = matsMap[
"ID"].AsUInteger();
357 catch (Exception e) {
358 m_log.Warn(
"[Materials]: cannot decode \"ID\" from matsMap: " + e.Message);
365 mat = matsMap[
"Material"] as
OSDMap;
369 m_log.Warn(
"[Materials]: cannot decode \"Material\" from matsMap: " + e.Message);
376 m_log.WarnFormat(
"[Materials]: SOP not found for localId: {0}", primLocalID.ToString());
380 if (!m_scene.Permissions.CanEditObject(sop.
UUID, agentID))
382 m_log.WarnFormat(
"User {0} can't edit object {1} {2}", agentID, sop.Name, sop.UUID);
386 Primitive.TextureEntry te =
new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length);
389 m_log.WarnFormat(
"[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID);
402 id = StoreMaterialAsAsset(agentID, mat, sop);
408 if (matsMap.ContainsKey(
"Face"))
410 face = matsMap[
"Face"].AsInteger();
411 Primitive.TextureEntryFace faceEntry = te.CreateFace((uint)face);
412 faceEntry.MaterialID = id;
416 if (te.DefaultTexture == null)
417 m_log.WarnFormat(
"[Materials]: TextureEntry.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID);
419 te.DefaultTexture.MaterialID = id;
425 sop.Shape.TextureEntry = te.GetBytes();
429 sop.TriggerScriptChangedEvent(Changed.TEXTURE);
430 sop.UpdateFlag = UpdateRequired.FULL;
431 sop.ParentGroup.HasGroupChanged =
true;
432 sop.ScheduleFullUpdate();
438 m_log.Warn(
"[Materials]: exception processing received material ", e);
448 m_log.Warn(
"[Materials]: exception decoding zipped CAP payload ", e);
454 resp[
"Zipped"] = ZCompressOSD(respArr,
false);
455 string response = OSDParser.SerializeLLSDXmlString(resp);
468 byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat));
469 using (var md5 = MD5.Create())
470 id =
new UUID(md5.ComputeHash(data), 0);
472 lock (m_regionMaterials)
474 if (!m_regionMaterials.ContainsKey(
id))
476 m_regionMaterials[id] = mat;
479 string name =
"Material " + ChooseMaterialName(mat, sop);
480 name = name.Substring(0, Math.Min(64, name.Length)).Trim();
483 m_scene.AssetService.Store(asset);
494 UUID normMap = mat[
"NormMap"].AsUUID();
495 if (normMap !=
UUID.Zero)
497 AssetBase asset = m_scene.AssetService.GetCached(normMap.ToString());
498 if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals(
"From IAR"))
502 UUID specMap = mat[
"SpecMap"].AsUUID();
503 if (specMap !=
UUID.Zero)
505 AssetBase asset = m_scene.AssetService.GetCached(specMap.ToString());
506 if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals(
"From IAR"))
510 if (sop.
Name !=
"Primitive")
513 if ((sop.
ParentGroup != null) && (sop.ParentGroup.Name !=
"Primitive"))
514 return sop.ParentGroup.Name;
526 lock (m_regionMaterials)
528 foreach (KeyValuePair<UUID, OSDMap> kvp
in m_regionMaterials)
532 matMap[
"ID"] = OSD.FromBinary(kvp.Key.GetBytes());
533 matMap[
"Material"] = kvp.Value;
539 resp[
"Zipped"] = ZCompressOSD(allOsd,
false);
541 return OSDParser.SerializeLLSDXmlString(resp);
544 private static string ZippedOsdBytesToString(byte[] bytes)
548 return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes));
552 return "ZippedOsdBytesToString caught an exception: " + e.ToString();
561 private static UUID HashOsd(
OSD osd)
563 byte[] data = OSDParser.SerializeLLSDBinary(osd,
false);
564 using (var md5 = MD5.Create())
565 return new UUID(md5.ComputeHash(data), 0);
572 byte[] data = OSDParser.SerializeLLSDBinary(inOsd, useHeader);
574 using (MemoryStream msSinkCompressed =
new MemoryStream())
576 using (Ionic.Zlib.ZlibStream zOut =
new Ionic.Zlib.ZlibStream(msSinkCompressed,
577 Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression,
true))
579 zOut.Write(data, 0, data.Length);
582 msSinkCompressed.Seek(0L, SeekOrigin.Begin);
583 osd = OSD.FromBinary(msSinkCompressed.ToArray());
594 using (MemoryStream msSinkUnCompressed =
new MemoryStream())
596 using (Ionic.Zlib.ZlibStream zOut =
new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress,
true))
598 zOut.Write(input, 0, input.Length);
601 msSinkUnCompressed.Seek(0L, SeekOrigin.Begin);
602 osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray());
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
string RenderMaterialsGetCap(string request)
OpenMetaverse.StructuredData.OSDArray OSDArray
OpenSim.Framework.SLUtil.OpenSimAssetType OpenSimAssetType
string RenderMaterialsPostCap(string request, UUID agentID)
static OSD ZDecompressBytesToOsd(byte[] input)
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
OpenMetaverse.StructuredData.OSDMap OSDMap
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures ca...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Asset class. All Assets are reference by this class or a class derived from this class ...
static OSD ZCompressOSD(OSD inOsd, bool useHeader)
OpenMetaverse.StructuredData.OSD OSD
Interactive OpenSim region server
OpenSim.Framework.SLUtil.OpenSimAssetType OpenSimAssetType
SceneObjectGroup ParentGroup
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
DAMap DynAttrs
Dynamic attributes can be created and deleted as required.
Material
Material type for a primitive
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
bool ContainsStore(string ns, string storeName)