From e8273fa8ad85323f18fb67ecf6d5f07eced87178 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Tue, 26 Nov 2013 10:37:32 +0200 Subject: - Materials: support the viewer removing the material (in which case matsMap["Material"] is missing) - Reduced logging --- .../Materials/MaterialsDemoModule.cs | 77 ++++++++++++---------- 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index d8f5563..44b1a4a 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -104,7 +104,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (!m_enabled) return; - m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE"); + m_log.DebugFormat("[MaterialsDemoModule]: Initialized"); } public void Close() @@ -112,7 +112,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (!m_enabled) return; - m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); + //m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); } public void AddRegion(Scene scene) @@ -120,7 +120,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (!m_enabled) return; - m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); + //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); m_scene = scene; m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; @@ -166,7 +166,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; // m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; - m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); } public void RegionLoaded(Scene scene) @@ -195,7 +195,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (part.DynAttrs == null) { - m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); + //m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); + return; } lock (part.DynAttrs) @@ -216,11 +217,11 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule return; } - m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); + //m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); if (matsArr == null) { - m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); + //m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); return; } @@ -238,7 +239,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } catch (Exception e) { - m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material: " + e.ToString()); + m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material ", e); } } } @@ -299,7 +300,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } catch (Exception e) { - m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart(): " + e.ToString()); + m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart() ", e); } } @@ -307,7 +308,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - m_log.Debug("[MaterialsDemoModule]: POST cap handler"); + //m_log.Debug("[MaterialsDemoModule]: POST cap handler"); OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); OSDMap resp = new OSDMap(); @@ -341,7 +342,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { if (m_knownMaterials.ContainsKey(id)) { - m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); + //m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); OSDMap matMap = new OSDMap(); matMap["ID"] = OSD.FromBinary(id.GetBytes()); @@ -374,34 +375,40 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { foreach (OSDMap matsMap in matsArr) { - m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); + //m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); - uint matLocalID = 0; - try { matLocalID = matsMap["ID"].AsUInteger(); } + uint primLocalID = 0; + try { primLocalID = matsMap["ID"].AsUInteger(); } catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } - m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); - + //m_log.Debug("[MaterialsDemoModule]: primLocalID: " + primLocalID.ToString()); OSDMap mat = null; try { mat = matsMap["Material"] as OSDMap; } catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } - m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); - - UUID id = HashOsd(mat); - lock (m_knownMaterials) - m_knownMaterials[id] = mat; - - - var sop = m_scene.GetSceneObjectPart(matLocalID); + //m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); + + UUID id; + if (mat == null) + { + id = UUID.Zero; + } + else + { + id = HashOsd(mat); + lock (m_knownMaterials) + m_knownMaterials[id] = mat; + } + + var sop = m_scene.GetSceneObjectPart(primLocalID); if (sop == null) - m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); + m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + primLocalID.ToString()); else { var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); if (te == null) { - m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); + m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + primLocalID.ToString()); } else { @@ -434,7 +441,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule te.DefaultTexture.MaterialID = id; } - m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); + //m_log.DebugFormat("[MaterialsDemoModule]: in \"{0}\", setting material ID for face {1} to {2}", sop.Name, face, id); //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually @@ -455,7 +462,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } catch (Exception e) { - m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); + m_log.Warn("[MaterialsDemoModule]: exception processing received material ", e); } } } @@ -465,10 +472,10 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } catch (Exception e) { - m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload: " + e.Message); + m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload ", e); //return ""; } - m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); + //m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); } @@ -476,8 +483,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule string response = OSDParser.SerializeLLSDXmlString(resp); //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); - m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); - m_log.Debug("[MaterialsDemoModule]: cap response: " + response); + //m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); + //m_log.Debug("[MaterialsDemoModule]: cap response: " + response); return response; } @@ -486,7 +493,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - m_log.Debug("[MaterialsDemoModule]: GET cap handler"); + //m_log.Debug("[MaterialsDemoModule]: GET cap handler"); OSDMap resp = new OSDMap(); int matsCount = 0; @@ -506,7 +513,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } resp["Zipped"] = ZCompressOSD(allOsd, false); - m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); + //m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); return OSDParser.SerializeLLSDXmlString(resp); } @@ -654,4 +661,4 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule // } // } } -} \ No newline at end of file +} -- cgit v1.1 From ca0336d8349382ddb46df4c7e7f6377c64151f25 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 5 Dec 2013 14:18:59 +0200 Subject: Renamed MaterialsDemoModule to MaterialsModule --- .../Materials/MaterialsDemoModule.cs | 664 --------------------- .../OptionalModules/Materials/MaterialsModule.cs | 664 +++++++++++++++++++++ 2 files changed, 664 insertions(+), 664 deletions(-) delete mode 100644 OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs create mode 100644 OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs deleted file mode 100644 index 44b1a4a..0000000 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Security.Cryptography; // for computing md5 hash -using log4net; -using Mono.Addins; -using Nini.Config; - -using OpenMetaverse; -using OpenMetaverse.StructuredData; - -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -using Ionic.Zlib; - -// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already -// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans -// the available DLLs -//[assembly: Addin("MaterialsDemoModule", "1.0")] -//[assembly: AddinDependency("OpenSim", "0.5")] - -namespace OpenSim.Region.OptionalModules.MaterialsDemoModule -{ - /// - /// - // # # ## ##### # # # # # #### - // # # # # # # ## # # ## # # # - // # # # # # # # # # # # # # # - // # ## # ###### ##### # # # # # # # # ### - // ## ## # # # # # ## # # ## # # - // # # # # # # # # # # # #### - // - // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION! - // - ////////////// WARNING ////////////////////////////////////////////////////////////////// - /// This is an *Experimental* module for developing support for materials-capable viewers - /// This module should NOT be used in a production environment! It may cause data corruption and - /// viewer crashes. It should be only used to evaluate implementations of materials. - /// - /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature - /// of OpenSimulator and is not field proven at the time this module was written. Persistence - /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials - /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means - /// of archiving however the texture resources used by these materials probably will not as they - /// may not be adequately referenced to ensure proper archiving. - /// - /// - /// - /// To enable this module, add this string at the bottom of OpenSim.ini: - /// [MaterialsDemoModule] - /// - /// - /// - - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] - public class MaterialsDemoModule : INonSharedRegionModule - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public string Name { get { return "MaterialsDemoModule"; } } - - public Type ReplaceableInterface { get { return null; } } - - private Scene m_scene = null; - private bool m_enabled = false; - - public Dictionary m_knownMaterials = new Dictionary(); - - public void Initialise(IConfigSource source) - { - m_enabled = (source.Configs["MaterialsDemoModule"] != null); - if (!m_enabled) - return; - - m_log.DebugFormat("[MaterialsDemoModule]: Initialized"); - } - - public void Close() - { - if (!m_enabled) - return; - - //m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); - } - - public void AddRegion(Scene scene) - { - if (!m_enabled) - return; - - //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); - - m_scene = scene; - m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; - m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; -// m_scene.EventManager.OnGatherUuids += GatherMaterialsUuids; - } - - void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) - { - foreach (var part in obj.Parts) - if (part != null) - GetStoredMaterialsForPart(part); - } - - void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) - { - string capsBase = "/CAPS/" + caps.CapsObjectPath; - - IRequestHandler renderMaterialsPostHandler - = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); - caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); - - // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET - // and POST handlers, (at least at the time this was originally written), so we first set up a POST - // handler normally and then add a GET handler via MainServer - - IRequestHandler renderMaterialsGetHandler - = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap, "RenderMaterials", null); - MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); - - // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well - IRequestHandler renderMaterialsPutHandler - = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); - MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); - } - - public void RemoveRegion(Scene scene) - { - if (!m_enabled) - return; - - m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; - m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; -// m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; - - //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); - } - - public void RegionLoaded(Scene scene) - { - } - - OSDMap GetMaterial(UUID id) - { - OSDMap map = null; - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(id)) - { - map = new OSDMap(); - map["ID"] = OSD.FromBinary(id.GetBytes()); - map["Material"] = m_knownMaterials[id]; - } - } - return map; - } - - void GetStoredMaterialsForPart(SceneObjectPart part) - { - OSD OSMaterials = null; - OSDArray matsArr = null; - - if (part.DynAttrs == null) - { - //m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); - return; - } - - lock (part.DynAttrs) - { - if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) - { - OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); - - if (materialsStore == null) - return; - - materialsStore.TryGetValue("Materials", out OSMaterials); - } - - if (OSMaterials != null && OSMaterials is OSDArray) - matsArr = OSMaterials as OSDArray; - else - return; - } - - //m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); - - if (matsArr == null) - { - //m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); - return; - } - - foreach (OSD elemOsd in matsArr) - { - if (elemOsd != null && elemOsd is OSDMap) - { - OSDMap matMap = elemOsd as OSDMap; - if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) - { - try - { - lock (m_knownMaterials) - m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material ", e); - } - } - } - } - } - - void StoreMaterialsForPart(SceneObjectPart part) - { - try - { - if (part == null || part.Shape == null) - return; - - Dictionary mats = new Dictionary(); - - Primitive.TextureEntry te = part.Shape.Textures; - - if (te.DefaultTexture != null) - { - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) - mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; - } - } - - if (te.FaceTextures != null) - { - foreach (var face in te.FaceTextures) - { - if (face != null) - { - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(face.MaterialID)) - mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; - } - } - } - } - if (mats.Count == 0) - return; - - OSDArray matsArr = new OSDArray(); - foreach (KeyValuePair kvp in mats) - { - OSDMap matOsd = new OSDMap(); - matOsd["ID"] = OSD.FromUUID(kvp.Key); - matOsd["Material"] = kvp.Value; - matsArr.Add(matOsd); - } - - OSDMap OSMaterials = new OSDMap(); - OSMaterials["Materials"] = matsArr; - - lock (part.DynAttrs) - part.DynAttrs.SetStore("OpenSim", "Materials", OSMaterials); - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart() ", e); - } - } - - public string RenderMaterialsPostCap(string request, string path, - string param, IOSHttpRequest httpRequest, - IOSHttpResponse httpResponse) - { - //m_log.Debug("[MaterialsDemoModule]: POST cap handler"); - - OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); - OSDMap resp = new OSDMap(); - - OSDMap materialsFromViewer = null; - - OSDArray respArr = new OSDArray(); - - if (req.ContainsKey("Zipped")) - { - OSD osd = null; - - byte[] inBytes = req["Zipped"].AsBinary(); - - try - { - osd = ZDecompressBytesToOsd(inBytes); - - if (osd != null) - { - if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries - { - foreach (OSD elem in (OSDArray)osd) - { - - try - { - UUID id = new UUID(elem.AsBinary(), 0); - - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(id)) - { - //m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); - OSDMap matMap = new OSDMap(); - matMap["ID"] = OSD.FromBinary(id.GetBytes()); - - matMap["Material"] = m_knownMaterials[id]; - respArr.Add(matMap); - } - else - m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); - } - } - catch (Exception e) - { - // report something here? - continue; - } - } - } - else if (osd is OSDMap) // reqest to assign a material - { - materialsFromViewer = osd as OSDMap; - - if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) - { - OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; - if (matsOsd is OSDArray) - { - OSDArray matsArr = matsOsd as OSDArray; - - try - { - foreach (OSDMap matsMap in matsArr) - { - //m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); - - uint primLocalID = 0; - try { primLocalID = matsMap["ID"].AsUInteger(); } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } - //m_log.Debug("[MaterialsDemoModule]: primLocalID: " + primLocalID.ToString()); - - OSDMap mat = null; - try { mat = matsMap["Material"] as OSDMap; } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } - //m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); - - UUID id; - if (mat == null) - { - id = UUID.Zero; - } - else - { - id = HashOsd(mat); - lock (m_knownMaterials) - m_knownMaterials[id] = mat; - } - - var sop = m_scene.GetSceneObjectPart(primLocalID); - if (sop == null) - m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + primLocalID.ToString()); - else - { - var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); - - if (te == null) - { - m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + primLocalID.ToString()); - } - else - { - int face = -1; - - if (matsMap.ContainsKey("Face")) - { - face = matsMap["Face"].AsInteger(); - if (te.FaceTextures == null) // && face == 0) - { - if (te.DefaultTexture == null) - m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); - else - te.DefaultTexture.MaterialID = id; - } - else - { - if (te.FaceTextures.Length >= face - 1) - { - if (te.FaceTextures[face] == null) - te.DefaultTexture.MaterialID = id; - else - te.FaceTextures[face].MaterialID = id; - } - } - } - else - { - if (te.DefaultTexture != null) - te.DefaultTexture.MaterialID = id; - } - - //m_log.DebugFormat("[MaterialsDemoModule]: in \"{0}\", setting material ID for face {1} to {2}", sop.Name, face, id); - - //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually - - if (sop.ParentGroup != null) - { - sop.Shape.TextureEntry = te.GetBytes(); - sop.TriggerScriptChangedEvent(Changed.TEXTURE); - sop.UpdateFlag = UpdateRequired.FULL; - sop.ParentGroup.HasGroupChanged = true; - - sop.ScheduleFullUpdate(); - - StoreMaterialsForPart(sop); - } - } - } - } - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception processing received material ", e); - } - } - } - } - } - - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload ", e); - //return ""; - } - //m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); - } - - - resp["Zipped"] = ZCompressOSD(respArr, false); - string response = OSDParser.SerializeLLSDXmlString(resp); - - //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); - //m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); - //m_log.Debug("[MaterialsDemoModule]: cap response: " + response); - return response; - } - - - public string RenderMaterialsGetCap(string request, string path, - string param, IOSHttpRequest httpRequest, - IOSHttpResponse httpResponse) - { - //m_log.Debug("[MaterialsDemoModule]: GET cap handler"); - - OSDMap resp = new OSDMap(); - int matsCount = 0; - OSDArray allOsd = new OSDArray(); - - lock (m_knownMaterials) - { - foreach (KeyValuePair kvp in m_knownMaterials) - { - OSDMap matMap = new OSDMap(); - - matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); - matMap["Material"] = kvp.Value; - allOsd.Add(matMap); - matsCount++; - } - } - - resp["Zipped"] = ZCompressOSD(allOsd, false); - //m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); - - return OSDParser.SerializeLLSDXmlString(resp); - } - - static string ZippedOsdBytesToString(byte[] bytes) - { - try - { - return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes)); - } - catch (Exception e) - { - return "ZippedOsdBytesToString caught an exception: " + e.ToString(); - } - } - - /// - /// computes a UUID by hashing a OSD object - /// - /// - /// - private static UUID HashOsd(OSD osd) - { - using (var md5 = MD5.Create()) - using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) - return new UUID(md5.ComputeHash(ms), 0); - } - - public static OSD ZCompressOSD(OSD inOsd, bool useHeader) - { - OSD osd = null; - - using (MemoryStream msSinkCompressed = new MemoryStream()) - { - using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, - Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) - { - CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); - zOut.Close(); - } - - msSinkCompressed.Seek(0L, SeekOrigin.Begin); - osd = OSD.FromBinary( msSinkCompressed.ToArray()); - } - - return osd; - } - - - public static OSD ZDecompressBytesToOsd(byte[] input) - { - OSD osd = null; - - using (MemoryStream msSinkUnCompressed = new MemoryStream()) - { - using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) - { - CopyStream(new MemoryStream(input), zOut); - zOut.Close(); - } - msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); - osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); - } - - return osd; - } - - static void CopyStream(System.IO.Stream input, System.IO.Stream output) - { - byte[] buffer = new byte[2048]; - int len; - while ((len = input.Read(buffer, 0, 2048)) > 0) - { - output.Write(buffer, 0, len); - } - - output.Flush(); - } - - // FIXME: This code is currently still in UuidGatherer since we cannot use Scene.EventManager as some - // calls to the gatherer are done for objects with no scene. -// /// -// /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps -// /// -// /// -// /// -// private void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) -// { -// // scan thru the dynAttrs map of this part for any textures used as materials -// OSD osdMaterials = null; -// -// lock (part.DynAttrs) -// { -// if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) -// { -// OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); -// if (materialsStore == null) -// return; -// -// materialsStore.TryGetValue("Materials", out osdMaterials); -// } -// -// if (osdMaterials != null) -// { -// //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); -// -// if (osdMaterials is OSDArray) -// { -// OSDArray matsArr = osdMaterials as OSDArray; -// foreach (OSDMap matMap in matsArr) -// { -// try -// { -// if (matMap.ContainsKey("Material")) -// { -// OSDMap mat = matMap["Material"] as OSDMap; -// if (mat.ContainsKey("NormMap")) -// { -// UUID normalMapId = mat["NormMap"].AsUUID(); -// if (normalMapId != UUID.Zero) -// { -// assetUuids[normalMapId] = AssetType.Texture; -// //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); -// } -// } -// if (mat.ContainsKey("SpecMap")) -// { -// UUID specularMapId = mat["SpecMap"].AsUUID(); -// if (specularMapId != UUID.Zero) -// { -// assetUuids[specularMapId] = AssetType.Texture; -// //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); -// } -// } -// } -// -// } -// catch (Exception e) -// { -// m_log.Warn("[MaterialsDemoModule]: exception getting materials: " + e.Message); -// } -// } -// } -// } -// } -// } - } -} diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs new file mode 100644 index 0000000..e707154 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -0,0 +1,664 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Security.Cryptography; // for computing md5 hash +using log4net; +using Mono.Addins; +using Nini.Config; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using Ionic.Zlib; + +// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already +// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans +// the available DLLs +//[assembly: Addin("MaterialsDemoModule", "1.0")] +//[assembly: AddinDependency("OpenSim", "0.5")] + +namespace OpenSim.Region.OptionalModules.MaterialsDemoModule +{ + /// + /// + // # # ## ##### # # # # # #### + // # # # # # # ## # # ## # # # + // # # # # # # # # # # # # # # + // # ## # ###### ##### # # # # # # # # ### + // ## ## # # # # # ## # # ## # # + // # # # # # # # # # # # #### + // + // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION! + // + ////////////// WARNING ////////////////////////////////////////////////////////////////// + /// This is an *Experimental* module for developing support for materials-capable viewers + /// This module should NOT be used in a production environment! It may cause data corruption and + /// viewer crashes. It should be only used to evaluate implementations of materials. + /// + /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature + /// of OpenSimulator and is not field proven at the time this module was written. Persistence + /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials + /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means + /// of archiving however the texture resources used by these materials probably will not as they + /// may not be adequately referenced to ensure proper archiving. + /// + /// + /// + /// To enable this module, add this string at the bottom of OpenSim.ini: + /// [MaterialsDemoModule] + /// + /// + /// + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] + public class MaterialsDemoModule : INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public string Name { get { return "MaterialsDemoModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + private Scene m_scene = null; + private bool m_enabled = false; + + public Dictionary m_knownMaterials = new Dictionary(); + + public void Initialise(IConfigSource source) + { + m_enabled = (source.Configs["MaterialsDemoModule"] != null); + if (!m_enabled) + return; + + m_log.DebugFormat("[MaterialsDemoModule]: Initialized"); + } + + public void Close() + { + if (!m_enabled) + return; + + //m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { + if (!m_enabled) + return; + + //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); + + m_scene = scene; + m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; + m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; +// m_scene.EventManager.OnGatherUuids += GatherMaterialsUuids; + } + + void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) + { + foreach (var part in obj.Parts) + if (part != null) + GetStoredMaterialsForPart(part); + } + + void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) + { + string capsBase = "/CAPS/" + caps.CapsObjectPath; + + IRequestHandler renderMaterialsPostHandler + = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); + caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); + + // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET + // and POST handlers, (at least at the time this was originally written), so we first set up a POST + // handler normally and then add a GET handler via MainServer + + IRequestHandler renderMaterialsGetHandler + = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap, "RenderMaterials", null); + MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); + + // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well + IRequestHandler renderMaterialsPutHandler + = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); + MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); + } + + public void RemoveRegion(Scene scene) + { + if (!m_enabled) + return; + + m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; + m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; +// m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; + + //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + } + + public void RegionLoaded(Scene scene) + { + } + + OSDMap GetMaterial(UUID id) + { + OSDMap map = null; + lock (m_knownMaterials) + { + if (m_knownMaterials.ContainsKey(id)) + { + map = new OSDMap(); + map["ID"] = OSD.FromBinary(id.GetBytes()); + map["Material"] = m_knownMaterials[id]; + } + } + return map; + } + + void GetStoredMaterialsForPart(SceneObjectPart part) + { + OSD OSMaterials = null; + OSDArray matsArr = null; + + if (part.DynAttrs == null) + { + //m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); + return; + } + + lock (part.DynAttrs) + { + if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) + { + OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + + if (materialsStore == null) + return; + + materialsStore.TryGetValue("Materials", out OSMaterials); + } + + if (OSMaterials != null && OSMaterials is OSDArray) + matsArr = OSMaterials as OSDArray; + else + return; + } + + //m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); + + if (matsArr == null) + { + //m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); + return; + } + + foreach (OSD elemOsd in matsArr) + { + if (elemOsd != null && elemOsd is OSDMap) + { + OSDMap matMap = elemOsd as OSDMap; + if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) + { + try + { + lock (m_knownMaterials) + m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material ", e); + } + } + } + } + } + + void StoreMaterialsForPart(SceneObjectPart part) + { + try + { + if (part == null || part.Shape == null) + return; + + Dictionary mats = new Dictionary(); + + Primitive.TextureEntry te = part.Shape.Textures; + + if (te.DefaultTexture != null) + { + lock (m_knownMaterials) + { + if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) + mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; + } + } + + if (te.FaceTextures != null) + { + foreach (var face in te.FaceTextures) + { + if (face != null) + { + lock (m_knownMaterials) + { + if (m_knownMaterials.ContainsKey(face.MaterialID)) + mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; + } + } + } + } + if (mats.Count == 0) + return; + + OSDArray matsArr = new OSDArray(); + foreach (KeyValuePair kvp in mats) + { + OSDMap matOsd = new OSDMap(); + matOsd["ID"] = OSD.FromUUID(kvp.Key); + matOsd["Material"] = kvp.Value; + matsArr.Add(matOsd); + } + + OSDMap OSMaterials = new OSDMap(); + OSMaterials["Materials"] = matsArr; + + lock (part.DynAttrs) + part.DynAttrs.SetStore("OpenSim", "Materials", OSMaterials); + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart() ", e); + } + } + + public string RenderMaterialsPostCap(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + //m_log.Debug("[MaterialsDemoModule]: POST cap handler"); + + OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); + OSDMap resp = new OSDMap(); + + OSDMap materialsFromViewer = null; + + OSDArray respArr = new OSDArray(); + + if (req.ContainsKey("Zipped")) + { + OSD osd = null; + + byte[] inBytes = req["Zipped"].AsBinary(); + + try + { + osd = ZDecompressBytesToOsd(inBytes); + + if (osd != null) + { + if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries + { + foreach (OSD elem in (OSDArray)osd) + { + + try + { + UUID id = new UUID(elem.AsBinary(), 0); + + lock (m_knownMaterials) + { + if (m_knownMaterials.ContainsKey(id)) + { + //m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); + OSDMap matMap = new OSDMap(); + matMap["ID"] = OSD.FromBinary(id.GetBytes()); + + matMap["Material"] = m_knownMaterials[id]; + respArr.Add(matMap); + } + else + m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); + } + } + catch (Exception e) + { + // report something here? + continue; + } + } + } + else if (osd is OSDMap) // reqest to assign a material + { + materialsFromViewer = osd as OSDMap; + + if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) + { + OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; + if (matsOsd is OSDArray) + { + OSDArray matsArr = matsOsd as OSDArray; + + try + { + foreach (OSDMap matsMap in matsArr) + { + //m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); + + uint primLocalID = 0; + try { primLocalID = matsMap["ID"].AsUInteger(); } + catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } + //m_log.Debug("[MaterialsDemoModule]: primLocalID: " + primLocalID.ToString()); + + OSDMap mat = null; + try { mat = matsMap["Material"] as OSDMap; } + catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } + //m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); + + UUID id; + if (mat == null) + { + id = UUID.Zero; + } + else + { + id = HashOsd(mat); + lock (m_knownMaterials) + m_knownMaterials[id] = mat; + } + + var sop = m_scene.GetSceneObjectPart(primLocalID); + if (sop == null) + m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + primLocalID.ToString()); + else + { + var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); + + if (te == null) + { + m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + primLocalID.ToString()); + } + else + { + int face = -1; + + if (matsMap.ContainsKey("Face")) + { + face = matsMap["Face"].AsInteger(); + if (te.FaceTextures == null) // && face == 0) + { + if (te.DefaultTexture == null) + m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); + else + te.DefaultTexture.MaterialID = id; + } + else + { + if (te.FaceTextures.Length >= face - 1) + { + if (te.FaceTextures[face] == null) + te.DefaultTexture.MaterialID = id; + else + te.FaceTextures[face].MaterialID = id; + } + } + } + else + { + if (te.DefaultTexture != null) + te.DefaultTexture.MaterialID = id; + } + + //m_log.DebugFormat("[MaterialsDemoModule]: in \"{0}\", setting material ID for face {1} to {2}", sop.Name, face, id); + + //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually + + if (sop.ParentGroup != null) + { + sop.Shape.TextureEntry = te.GetBytes(); + sop.TriggerScriptChangedEvent(Changed.TEXTURE); + sop.UpdateFlag = UpdateRequired.FULL; + sop.ParentGroup.HasGroupChanged = true; + + sop.ScheduleFullUpdate(); + + StoreMaterialsForPart(sop); + } + } + } + } + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception processing received material ", e); + } + } + } + } + } + + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload ", e); + //return ""; + } + //m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); + } + + + resp["Zipped"] = ZCompressOSD(respArr, false); + string response = OSDParser.SerializeLLSDXmlString(resp); + + //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); + //m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); + //m_log.Debug("[MaterialsDemoModule]: cap response: " + response); + return response; + } + + + public string RenderMaterialsGetCap(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + //m_log.Debug("[MaterialsDemoModule]: GET cap handler"); + + OSDMap resp = new OSDMap(); + int matsCount = 0; + OSDArray allOsd = new OSDArray(); + + lock (m_knownMaterials) + { + foreach (KeyValuePair kvp in m_knownMaterials) + { + OSDMap matMap = new OSDMap(); + + matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); + matMap["Material"] = kvp.Value; + allOsd.Add(matMap); + matsCount++; + } + } + + resp["Zipped"] = ZCompressOSD(allOsd, false); + //m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); + + return OSDParser.SerializeLLSDXmlString(resp); + } + + static string ZippedOsdBytesToString(byte[] bytes) + { + try + { + return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes)); + } + catch (Exception e) + { + return "ZippedOsdBytesToString caught an exception: " + e.ToString(); + } + } + + /// + /// computes a UUID by hashing a OSD object + /// + /// + /// + private static UUID HashOsd(OSD osd) + { + using (var md5 = MD5.Create()) + using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) + return new UUID(md5.ComputeHash(ms), 0); + } + + public static OSD ZCompressOSD(OSD inOsd, bool useHeader) + { + OSD osd = null; + + using (MemoryStream msSinkCompressed = new MemoryStream()) + { + using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, + Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); + zOut.Close(); + } + + msSinkCompressed.Seek(0L, SeekOrigin.Begin); + osd = OSD.FromBinary( msSinkCompressed.ToArray()); + } + + return osd; + } + + + public static OSD ZDecompressBytesToOsd(byte[] input) + { + OSD osd = null; + + using (MemoryStream msSinkUnCompressed = new MemoryStream()) + { + using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) + { + CopyStream(new MemoryStream(input), zOut); + zOut.Close(); + } + msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); + osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); + } + + return osd; + } + + static void CopyStream(System.IO.Stream input, System.IO.Stream output) + { + byte[] buffer = new byte[2048]; + int len; + while ((len = input.Read(buffer, 0, 2048)) > 0) + { + output.Write(buffer, 0, len); + } + + output.Flush(); + } + + // FIXME: This code is currently still in UuidGatherer since we cannot use Scene.EventManager as some + // calls to the gatherer are done for objects with no scene. +// /// +// /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps +// /// +// /// +// /// +// private void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) +// { +// // scan thru the dynAttrs map of this part for any textures used as materials +// OSD osdMaterials = null; +// +// lock (part.DynAttrs) +// { +// if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) +// { +// OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); +// if (materialsStore == null) +// return; +// +// materialsStore.TryGetValue("Materials", out osdMaterials); +// } +// +// if (osdMaterials != null) +// { +// //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); +// +// if (osdMaterials is OSDArray) +// { +// OSDArray matsArr = osdMaterials as OSDArray; +// foreach (OSDMap matMap in matsArr) +// { +// try +// { +// if (matMap.ContainsKey("Material")) +// { +// OSDMap mat = matMap["Material"] as OSDMap; +// if (mat.ContainsKey("NormMap")) +// { +// UUID normalMapId = mat["NormMap"].AsUUID(); +// if (normalMapId != UUID.Zero) +// { +// assetUuids[normalMapId] = AssetType.Texture; +// //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); +// } +// } +// if (mat.ContainsKey("SpecMap")) +// { +// UUID specularMapId = mat["SpecMap"].AsUUID(); +// if (specularMapId != UUID.Zero) +// { +// assetUuids[specularMapId] = AssetType.Texture; +// //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); +// } +// } +// } +// +// } +// catch (Exception e) +// { +// m_log.Warn("[MaterialsDemoModule]: exception getting materials: " + e.Message); +// } +// } +// } +// } +// } +// } + } +} -- cgit v1.1 From 3018b2c5d7c9de0e8da6d158f0848c840b7864ab Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Fri, 6 Dec 2013 16:21:11 +0200 Subject: Materials module: a) Store materials as assets; b) Finalized it (removed the "Demo" label; removed most of the logging); c) Enabled by default Changed UuidGatherer to use 'sbyte' to identify assets instead of 'AssetType'. This lets UuidGatherer handle Materials, which are defined in a different enum from 'AssetType'. --- .../OptionalModules/Materials/MaterialsModule.cs | 518 ++++++++------------- 1 file changed, 191 insertions(+), 327 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index e707154..09041e8 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -42,77 +42,49 @@ using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; using Ionic.Zlib; // You will need to uncomment these lines if you are adding a region module to some other assembly which does not already // specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans // the available DLLs -//[assembly: Addin("MaterialsDemoModule", "1.0")] +//[assembly: Addin("MaterialsModule", "1.0")] //[assembly: AddinDependency("OpenSim", "0.5")] -namespace OpenSim.Region.OptionalModules.MaterialsDemoModule +namespace OpenSim.Region.OptionalModules.Materials { - /// - /// - // # # ## ##### # # # # # #### - // # # # # # # ## # # ## # # # - // # # # # # # # # # # # # # # - // # ## # ###### ##### # # # # # # # # ### - // ## ## # # # # # ## # # ## # # - // # # # # # # # # # # # #### - // - // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION! - // - ////////////// WARNING ////////////////////////////////////////////////////////////////// - /// This is an *Experimental* module for developing support for materials-capable viewers - /// This module should NOT be used in a production environment! It may cause data corruption and - /// viewer crashes. It should be only used to evaluate implementations of materials. - /// - /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature - /// of OpenSimulator and is not field proven at the time this module was written. Persistence - /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials - /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means - /// of archiving however the texture resources used by these materials probably will not as they - /// may not be adequately referenced to ensure proper archiving. - /// - /// - /// - /// To enable this module, add this string at the bottom of OpenSim.ini: - /// [MaterialsDemoModule] - /// - /// - /// - - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] - public class MaterialsDemoModule : INonSharedRegionModule + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsModule")] + public class MaterialsModule : INonSharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public string Name { get { return "MaterialsDemoModule"; } } + public string Name { get { return "MaterialsModule"; } } public Type ReplaceableInterface { get { return null; } } private Scene m_scene = null; private bool m_enabled = false; - public Dictionary m_knownMaterials = new Dictionary(); + public Dictionary m_regionMaterials = new Dictionary(); public void Initialise(IConfigSource source) { - m_enabled = (source.Configs["MaterialsDemoModule"] != null); + IConfig config = source.Configs["Materials"]; + if (config == null) + return; + + m_enabled = config.GetBoolean("enable_materials", true); if (!m_enabled) return; - m_log.DebugFormat("[MaterialsDemoModule]: Initialized"); + m_log.DebugFormat("[Materials]: Initialized"); } public void Close() { if (!m_enabled) return; - - //m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); } public void AddRegion(Scene scene) @@ -120,22 +92,19 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (!m_enabled) return; - //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); - m_scene = scene; m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; -// m_scene.EventManager.OnGatherUuids += GatherMaterialsUuids; } - void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) + private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) { foreach (var part in obj.Parts) if (part != null) - GetStoredMaterialsForPart(part); + GetStoredMaterialsInPart(part); } - void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) + private void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) { string capsBase = "/CAPS/" + caps.CapsObjectPath; @@ -164,143 +133,65 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; -// m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; - - //m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); } public void RegionLoaded(Scene scene) { } - OSDMap GetMaterial(UUID id) - { - OSDMap map = null; - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(id)) - { - map = new OSDMap(); - map["ID"] = OSD.FromBinary(id.GetBytes()); - map["Material"] = m_knownMaterials[id]; - } - } - return map; - } - - void GetStoredMaterialsForPart(SceneObjectPart part) + /// + /// Find the materials used in the SOP, and add them to 'm_regionMaterials'. + /// + private void GetStoredMaterialsInPart(SceneObjectPart part) { - OSD OSMaterials = null; - OSDArray matsArr = null; - - if (part.DynAttrs == null) - { - //m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); + if (part.Shape == null) return; - } - - lock (part.DynAttrs) - { - if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) - { - OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); - - if (materialsStore == null) - return; - - materialsStore.TryGetValue("Materials", out OSMaterials); - } - - if (OSMaterials != null && OSMaterials is OSDArray) - matsArr = OSMaterials as OSDArray; - else - return; - } - - //m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); - - if (matsArr == null) - { - //m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); + var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); + if (te == null) return; - } - foreach (OSD elemOsd in matsArr) + GetStoredMaterialInFace(part, te.DefaultTexture); + + foreach (Primitive.TextureEntryFace face in te.FaceTextures) { - if (elemOsd != null && elemOsd is OSDMap) - { - OSDMap matMap = elemOsd as OSDMap; - if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) - { - try - { - lock (m_knownMaterials) - m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material ", e); - } - } - } + if (face != null) + GetStoredMaterialInFace(part, face); } } - void StoreMaterialsForPart(SceneObjectPart part) + /// + /// Find the materials used in one Face, and add them to 'm_regionMaterials'. + /// + private void GetStoredMaterialInFace(SceneObjectPart part, Primitive.TextureEntryFace face) { - try + UUID id = face.MaterialID; + if (id == UUID.Zero) + return; + + lock (m_regionMaterials) { - if (part == null || part.Shape == null) + if (m_regionMaterials.ContainsKey(id)) return; - - Dictionary mats = new Dictionary(); - - Primitive.TextureEntry te = part.Shape.Textures; - - if (te.DefaultTexture != null) + + byte[] data = m_scene.AssetService.GetData(id.ToString()); + if (data == null) { - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) - mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; - } + m_log.WarnFormat("[Materials]: Prim \"{0}\" ({1}) contains unknown material ID {2}", part.Name, part.UUID, id); + return; } - if (te.FaceTextures != null) + OSDMap mat; + try { - foreach (var face in te.FaceTextures) - { - if (face != null) - { - lock (m_knownMaterials) - { - if (m_knownMaterials.ContainsKey(face.MaterialID)) - mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; - } - } - } + mat = (OSDMap)OSDParser.DeserializeLLSDXml(data); } - if (mats.Count == 0) - return; - - OSDArray matsArr = new OSDArray(); - foreach (KeyValuePair kvp in mats) + catch (Exception e) { - OSDMap matOsd = new OSDMap(); - matOsd["ID"] = OSD.FromUUID(kvp.Key); - matOsd["Material"] = kvp.Value; - matsArr.Add(matOsd); + m_log.WarnFormat("[Materials]: cannot decode material asset {0}: {1}", id, e.Message); + return; } - OSDMap OSMaterials = new OSDMap(); - OSMaterials["Materials"] = matsArr; - - lock (part.DynAttrs) - part.DynAttrs.SetStore("OpenSim", "Materials", OSMaterials); - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart() ", e); + m_regionMaterials[id] = mat; } } @@ -308,8 +199,6 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - //m_log.Debug("[MaterialsDemoModule]: POST cap handler"); - OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); OSDMap resp = new OSDMap(); @@ -333,34 +222,38 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { foreach (OSD elem in (OSDArray)osd) { - try { UUID id = new UUID(elem.AsBinary(), 0); - lock (m_knownMaterials) + lock (m_regionMaterials) { - if (m_knownMaterials.ContainsKey(id)) + if (m_regionMaterials.ContainsKey(id)) { - //m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); OSDMap matMap = new OSDMap(); matMap["ID"] = OSD.FromBinary(id.GetBytes()); - - matMap["Material"] = m_knownMaterials[id]; + matMap["Material"] = m_regionMaterials[id]; respArr.Add(matMap); } else - m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); + { + m_log.Warn("[Materials]: request for unknown material ID: " + id.ToString()); + + // Theoretically we could try to load the material from the assets service, + // but that shouldn't be necessary because the viewer should only request + // materials that exist in a prim on the region, and all of these materials + // are already stored in m_regionMaterials. + } } } catch (Exception e) { - // report something here? + m_log.Error("Error getting materials in response to viewer request", e); continue; } } } - else if (osd is OSDMap) // reqest to assign a material + else if (osd is OSDMap) // request to assign a material { materialsFromViewer = osd as OSDMap; @@ -375,94 +268,118 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { foreach (OSDMap matsMap in matsArr) { - //m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); - uint primLocalID = 0; - try { primLocalID = matsMap["ID"].AsUInteger(); } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } - //m_log.Debug("[MaterialsDemoModule]: primLocalID: " + primLocalID.ToString()); + try { + primLocalID = matsMap["ID"].AsUInteger(); + } + catch (Exception e) { + m_log.Warn("[Materials]: cannot decode \"ID\" from matsMap: " + e.Message); + continue; + } OSDMap mat = null; - try { mat = matsMap["Material"] as OSDMap; } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } - //m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); + try + { + mat = matsMap["Material"] as OSDMap; + } + catch (Exception e) + { + m_log.Warn("[Materials]: cannot decode \"Material\" from matsMap: " + e.Message); + continue; + } + + SceneObjectPart sop = m_scene.GetSceneObjectPart(primLocalID); + if (sop == null) + { + m_log.WarnFormat("[Materials]: SOP not found for localId: {0}", primLocalID.ToString()); + continue; + } + + Primitive.TextureEntry te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); + if (te == null) + { + m_log.WarnFormat("[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID); + continue; + } + UUID id; if (mat == null) { + // This happens then the user removes a material from a prim id = UUID.Zero; } else { - id = HashOsd(mat); - lock (m_knownMaterials) - m_knownMaterials[id] = mat; + // Material UUID = hash of the material's data. + // This makes materials deduplicate across the entire grid (but isn't otherwise required). + byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); + using (var md5 = MD5.Create()) + id = new UUID(md5.ComputeHash(data), 0); + + lock (m_regionMaterials) + { + if (!m_regionMaterials.ContainsKey(id)) + { + m_regionMaterials[id] = mat; + + // This asset might exist already, but it's ok to try to store it again + string name = "Material " + ChooseMaterialName(mat, sop); + name = name.Substring(0, Math.Min(64, name.Length)).Trim(); + AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, sop.OwnerID.ToString()); + asset.Data = data; + m_scene.AssetService.Store(asset); + } + } } - var sop = m_scene.GetSceneObjectPart(primLocalID); - if (sop == null) - m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + primLocalID.ToString()); - else - { - var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); - if (te == null) + int face = -1; + + if (matsMap.ContainsKey("Face")) + { + face = matsMap["Face"].AsInteger(); + if (te.FaceTextures == null) // && face == 0) { - m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + primLocalID.ToString()); + if (te.DefaultTexture == null) + m_log.WarnFormat("[Materials]: te.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID); + else + te.DefaultTexture.MaterialID = id; } else { - int face = -1; - - if (matsMap.ContainsKey("Face")) - { - face = matsMap["Face"].AsInteger(); - if (te.FaceTextures == null) // && face == 0) - { - if (te.DefaultTexture == null) - m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); - else - te.DefaultTexture.MaterialID = id; - } - else - { - if (te.FaceTextures.Length >= face - 1) - { - if (te.FaceTextures[face] == null) - te.DefaultTexture.MaterialID = id; - else - te.FaceTextures[face].MaterialID = id; - } - } - } - else + if (te.FaceTextures.Length >= face - 1) { - if (te.DefaultTexture != null) + if (te.FaceTextures[face] == null) te.DefaultTexture.MaterialID = id; + else + te.FaceTextures[face].MaterialID = id; } + } + } + else + { + if (te.DefaultTexture != null) + te.DefaultTexture.MaterialID = id; + } - //m_log.DebugFormat("[MaterialsDemoModule]: in \"{0}\", setting material ID for face {1} to {2}", sop.Name, face, id); - - //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually - - if (sop.ParentGroup != null) - { - sop.Shape.TextureEntry = te.GetBytes(); - sop.TriggerScriptChangedEvent(Changed.TEXTURE); - sop.UpdateFlag = UpdateRequired.FULL; - sop.ParentGroup.HasGroupChanged = true; + //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); - sop.ScheduleFullUpdate(); + // We can't use sop.UpdateTextureEntry(te) because it filters, so do it manually + sop.Shape.TextureEntry = te.GetBytes(); - StoreMaterialsForPart(sop); - } - } + if (sop.ParentGroup != null) + { + sop.TriggerScriptChangedEvent(Changed.TEXTURE); + sop.UpdateFlag = UpdateRequired.FULL; + sop.ParentGroup.HasGroupChanged = true; + sop.ScheduleFullUpdate(); } } } catch (Exception e) { - m_log.Warn("[MaterialsDemoModule]: exception processing received material ", e); + m_log.Warn("[Materials]: exception processing received material ", e); } } } @@ -472,36 +389,63 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } catch (Exception e) { - m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload ", e); + m_log.Warn("[Materials]: exception decoding zipped CAP payload ", e); //return ""; } - //m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); } resp["Zipped"] = ZCompressOSD(respArr, false); string response = OSDParser.SerializeLLSDXmlString(resp); - //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); - //m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); - //m_log.Debug("[MaterialsDemoModule]: cap response: " + response); + //m_log.Debug("[Materials]: cap request: " + request); + //m_log.Debug("[Materials]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); + //m_log.Debug("[Materials]: cap response: " + response); return response; } + /// + /// Use heuristics to choose a good name for the material. + /// + private string ChooseMaterialName(OSDMap mat, SceneObjectPart sop) + { + UUID normMap = mat["NormMap"].AsUUID(); + if (normMap != UUID.Zero) + { + AssetBase asset = m_scene.AssetService.GetCached(normMap.ToString()); + if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR")) + return asset.Name; + } + + UUID specMap = mat["SpecMap"].AsUUID(); + if (specMap != UUID.Zero) + { + AssetBase asset = m_scene.AssetService.GetCached(specMap.ToString()); + if ((asset != null) && (asset.Name.Length > 0) && !asset.Name.Equals("From IAR")) + return asset.Name; + } + + if (sop.Name != "Primitive") + return sop.Name; + + if ((sop.ParentGroup != null) && (sop.ParentGroup.Name != "Primitive")) + return sop.ParentGroup.Name; + + return ""; + } + public string RenderMaterialsGetCap(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - //m_log.Debug("[MaterialsDemoModule]: GET cap handler"); - OSDMap resp = new OSDMap(); int matsCount = 0; OSDArray allOsd = new OSDArray(); - lock (m_knownMaterials) + lock (m_regionMaterials) { - foreach (KeyValuePair kvp in m_knownMaterials) + foreach (KeyValuePair kvp in m_regionMaterials) { OSDMap matMap = new OSDMap(); @@ -513,12 +457,11 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } resp["Zipped"] = ZCompressOSD(allOsd, false); - //m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); return OSDParser.SerializeLLSDXmlString(resp); } - static string ZippedOsdBytesToString(byte[] bytes) + private static string ZippedOsdBytesToString(byte[] bytes) { try { @@ -537,26 +480,27 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule /// private static UUID HashOsd(OSD osd) { + byte[] data = OSDParser.SerializeLLSDBinary(osd, false); using (var md5 = MD5.Create()) - using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) - return new UUID(md5.ComputeHash(ms), 0); + return new UUID(md5.ComputeHash(data), 0); } public static OSD ZCompressOSD(OSD inOsd, bool useHeader) { OSD osd = null; + byte[] data = OSDParser.SerializeLLSDBinary(inOsd, useHeader); + using (MemoryStream msSinkCompressed = new MemoryStream()) { using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) { - CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); - zOut.Close(); + zOut.Write(data, 0, data.Length); } msSinkCompressed.Seek(0L, SeekOrigin.Begin); - osd = OSD.FromBinary( msSinkCompressed.ToArray()); + osd = OSD.FromBinary(msSinkCompressed.ToArray()); } return osd; @@ -571,94 +515,14 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) { - CopyStream(new MemoryStream(input), zOut); - zOut.Close(); + zOut.Write(input, 0, input.Length); } + msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); } return osd; } - - static void CopyStream(System.IO.Stream input, System.IO.Stream output) - { - byte[] buffer = new byte[2048]; - int len; - while ((len = input.Read(buffer, 0, 2048)) > 0) - { - output.Write(buffer, 0, len); - } - - output.Flush(); - } - - // FIXME: This code is currently still in UuidGatherer since we cannot use Scene.EventManager as some - // calls to the gatherer are done for objects with no scene. -// /// -// /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps -// /// -// /// -// /// -// private void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) -// { -// // scan thru the dynAttrs map of this part for any textures used as materials -// OSD osdMaterials = null; -// -// lock (part.DynAttrs) -// { -// if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) -// { -// OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); -// if (materialsStore == null) -// return; -// -// materialsStore.TryGetValue("Materials", out osdMaterials); -// } -// -// if (osdMaterials != null) -// { -// //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); -// -// if (osdMaterials is OSDArray) -// { -// OSDArray matsArr = osdMaterials as OSDArray; -// foreach (OSDMap matMap in matsArr) -// { -// try -// { -// if (matMap.ContainsKey("Material")) -// { -// OSDMap mat = matMap["Material"] as OSDMap; -// if (mat.ContainsKey("NormMap")) -// { -// UUID normalMapId = mat["NormMap"].AsUUID(); -// if (normalMapId != UUID.Zero) -// { -// assetUuids[normalMapId] = AssetType.Texture; -// //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); -// } -// } -// if (mat.ContainsKey("SpecMap")) -// { -// UUID specularMapId = mat["SpecMap"].AsUUID(); -// if (specularMapId != UUID.Zero) -// { -// assetUuids[specularMapId] = AssetType.Texture; -// //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); -// } -// } -// } -// -// } -// catch (Exception e) -// { -// m_log.Warn("[MaterialsDemoModule]: exception getting materials: " + e.Message); -// } -// } -// } -// } -// } -// } } } -- cgit v1.1 From 68d83425c6b39614210b28e97d5006a882ea3097 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 12 Dec 2013 15:14:24 +0200 Subject: When asked to change the Material for one face, change only that face; not the default material --- .../OptionalModules/Materials/MaterialsModule.cs | 23 +++++----------------- 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 09041e8..9779594 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -339,27 +339,14 @@ namespace OpenSim.Region.OptionalModules.Materials if (matsMap.ContainsKey("Face")) { face = matsMap["Face"].AsInteger(); - if (te.FaceTextures == null) // && face == 0) - { - if (te.DefaultTexture == null) - m_log.WarnFormat("[Materials]: te.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID); - else - te.DefaultTexture.MaterialID = id; - } - else - { - if (te.FaceTextures.Length >= face - 1) - { - if (te.FaceTextures[face] == null) - te.DefaultTexture.MaterialID = id; - else - te.FaceTextures[face].MaterialID = id; - } - } + Primitive.TextureEntryFace faceEntry = te.CreateFace((uint)face); + faceEntry.MaterialID = id; } else { - if (te.DefaultTexture != null) + if (te.DefaultTexture == null) + m_log.WarnFormat("[Materials]: TextureEntry.DefaultTexture is null in {0} {1}", sop.Name, sop.UUID); + else te.DefaultTexture.MaterialID = id; } -- cgit v1.1 From d1f16c4b4b3f5c0938f3f0572c70e92cb90b6a0b Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Sun, 5 Jan 2014 14:03:10 +0200 Subject: Check agent permissions before modifying an object's materials. Also, when creating a Material asset, set the current agent as the Creator. --- .../OptionalModules/Materials/MaterialsModule.cs | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 9779594..4b635d8 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -109,7 +109,10 @@ namespace OpenSim.Region.OptionalModules.Materials string capsBase = "/CAPS/" + caps.CapsObjectPath; IRequestHandler renderMaterialsPostHandler - = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); + = new RestStreamHandler("POST", capsBase + "/", + (request, path, param, httpRequest, httpResponse) + => RenderMaterialsPostCap(request, agentID), + "RenderMaterials", null); caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET @@ -117,12 +120,18 @@ namespace OpenSim.Region.OptionalModules.Materials // handler normally and then add a GET handler via MainServer IRequestHandler renderMaterialsGetHandler - = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap, "RenderMaterials", null); + = new RestStreamHandler("GET", capsBase + "/", + (request, path, param, httpRequest, httpResponse) + => RenderMaterialsGetCap(request), + "RenderMaterials", null); MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well IRequestHandler renderMaterialsPutHandler - = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); + = new RestStreamHandler("PUT", capsBase + "/", + (request, path, param, httpRequest, httpResponse) + => RenderMaterialsPostCap(request, agentID), + "RenderMaterials", null); MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); } @@ -195,9 +204,7 @@ namespace OpenSim.Region.OptionalModules.Materials } } - public string RenderMaterialsPostCap(string request, string path, - string param, IOSHttpRequest httpRequest, - IOSHttpResponse httpResponse) + public string RenderMaterialsPostCap(string request, UUID agentID) { OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); OSDMap resp = new OSDMap(); @@ -295,6 +302,12 @@ namespace OpenSim.Region.OptionalModules.Materials continue; } + if (!m_scene.Permissions.CanEditObject(sop.UUID, agentID)) + { + m_log.WarnFormat("User {0} can't edit object {1} {2}", agentID, sop.Name, sop.UUID); + continue; + } + Primitive.TextureEntry te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); if (te == null) { @@ -326,7 +339,7 @@ namespace OpenSim.Region.OptionalModules.Materials // This asset might exist already, but it's ok to try to store it again string name = "Material " + ChooseMaterialName(mat, sop); name = name.Substring(0, Math.Min(64, name.Length)).Trim(); - AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, sop.OwnerID.ToString()); + AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString()); asset.Data = data; m_scene.AssetService.Store(asset); } @@ -422,9 +435,7 @@ namespace OpenSim.Region.OptionalModules.Materials } - public string RenderMaterialsGetCap(string request, string path, - string param, IOSHttpRequest httpRequest, - IOSHttpResponse httpResponse) + public string RenderMaterialsGetCap(string request) { OSDMap resp = new OSDMap(); int matsCount = 0; -- cgit v1.1 From 28723beb0ccec654ac24ee1632b137b424fd3360 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 20 Jan 2014 02:57:08 -0800 Subject: Add code to convert legacy materials stored in DynAttrs to new asset format and store them as assets --- .../OptionalModules/Materials/MaterialsModule.cs | 122 +++++++++++++++++---- 1 file changed, 102 insertions(+), 20 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 4b635d8..1b5a7a3 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -149,12 +149,87 @@ namespace OpenSim.Region.OptionalModules.Materials } /// + /// Searches the part for any legacy materials stored in DynAttrs and converts them to assets, replacing + /// the MaterialIDs in the TextureEntries for the part. + /// Deletes the legacy materials from the part as they are no longer needed. + /// + /// + private void ConvertLegacyMaterialsInPart(SceneObjectPart part) + { + if (part.DynAttrs == null) + return; + + var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); + if (te == null) + return; + + OSD OSMaterials = null; + OSDArray matsArr = null; + + lock (part.DynAttrs) + { + if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) + { + OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + + if (materialsStore == null) + return; + + materialsStore.TryGetValue("Materials", out OSMaterials); + } + + if (OSMaterials != null && OSMaterials is OSDArray) + matsArr = OSMaterials as OSDArray; + else + return; + } + + if (matsArr == null) + return; + + foreach (OSD elemOsd in matsArr) + { + if (elemOsd != null && elemOsd is OSDMap) + { + OSDMap matMap = elemOsd as OSDMap; + if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) + { + UUID id = matMap["ID"].AsUUID(); + OSDMap material = (OSDMap)matMap["Material"]; + bool used = false; + + foreach (var face in te.FaceTextures) + if (face.MaterialID == id) + used = true; + + if (used) + { // store legacy material in new asset format, and update the part texture entry with the new hashed UUID + + var newId = StoreMaterialAsAsset(part.CreatorID, material, part); + foreach (var face in te.FaceTextures) + if (face.MaterialID == id) + face.MaterialID = newId; + } + } + } + } + + part.Shape.TextureEntry = te.GetBytes(); + + lock (part.DynAttrs) + part.DynAttrs.RemoveStore("OpenSim", "Materials"); + } + + /// /// Find the materials used in the SOP, and add them to 'm_regionMaterials'. /// private void GetStoredMaterialsInPart(SceneObjectPart part) { if (part.Shape == null) return; + + ConvertLegacyMaterialsInPart(part); + var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); if (te == null) return; @@ -324,26 +399,7 @@ namespace OpenSim.Region.OptionalModules.Materials } else { - // Material UUID = hash of the material's data. - // This makes materials deduplicate across the entire grid (but isn't otherwise required). - byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); - using (var md5 = MD5.Create()) - id = new UUID(md5.ComputeHash(data), 0); - - lock (m_regionMaterials) - { - if (!m_regionMaterials.ContainsKey(id)) - { - m_regionMaterials[id] = mat; - - // This asset might exist already, but it's ok to try to store it again - string name = "Material " + ChooseMaterialName(mat, sop); - name = name.Substring(0, Math.Min(64, name.Length)).Trim(); - AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString()); - asset.Data = data; - m_scene.AssetService.Store(asset); - } - } + id = StoreMaterialAsAsset(agentID, mat, sop); } @@ -404,6 +460,32 @@ namespace OpenSim.Region.OptionalModules.Materials return response; } + private UUID StoreMaterialAsAsset(UUID agentID, OSDMap mat, SceneObjectPart sop) + { + UUID id; + // Material UUID = hash of the material's data. + // This makes materials deduplicate across the entire grid (but isn't otherwise required). + byte[] data = System.Text.Encoding.ASCII.GetBytes(OSDParser.SerializeLLSDXmlString(mat)); + using (var md5 = MD5.Create()) + id = new UUID(md5.ComputeHash(data), 0); + + lock (m_regionMaterials) + { + if (!m_regionMaterials.ContainsKey(id)) + { + m_regionMaterials[id] = mat; + + // This asset might exist already, but it's ok to try to store it again + string name = "Material " + ChooseMaterialName(mat, sop); + name = name.Substring(0, Math.Min(64, name.Length)).Trim(); + AssetBase asset = new AssetBase(id, name, (sbyte)OpenSimAssetType.Material, agentID.ToString()); + asset.Data = data; + m_scene.AssetService.Store(asset); + } + } + return id; + } + /// /// Use heuristics to choose a good name for the material. /// -- cgit v1.1 From 95c926b2cd8585dd5b84ad7827d21b6122ea1001 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 20 Jan 2014 03:02:30 -0800 Subject: delay texture entry parsing until absolutely necessary while converting legacy materials --- OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 1b5a7a3..d8ec979 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -159,10 +159,6 @@ namespace OpenSim.Region.OptionalModules.Materials if (part.DynAttrs == null) return; - var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); - if (te == null) - return; - OSD OSMaterials = null; OSDArray matsArr = null; @@ -187,6 +183,10 @@ namespace OpenSim.Region.OptionalModules.Materials if (matsArr == null) return; + var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); + if (te == null) + return; + foreach (OSD elemOsd in matsArr) { if (elemOsd != null && elemOsd is OSDMap) -- cgit v1.1 From 36d8a24a867fbbc95214653fec463aced8ba7c5f Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 20 Jan 2014 03:11:01 -0800 Subject: force SOG update when converting legacy materials to ensure changes are persisted --- OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index d8ec979..ce2a56a 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -215,6 +215,8 @@ namespace OpenSim.Region.OptionalModules.Materials } part.Shape.TextureEntry = te.GetBytes(); + part.ParentGroup.HasGroupChanged = true; + part.ScheduleFullUpdate(); lock (part.DynAttrs) part.DynAttrs.RemoveStore("OpenSim", "Materials"); -- cgit v1.1 From 2e78e89c36e661f72773e54f97bec3f04af67b79 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 20 Jan 2014 11:33:49 -0800 Subject: Clean up orphaned json stores. This can happen when an object is removed, when a script is removed, or when a script is reset. Also added a stats command to track the number of json stores used by a region. Will probably add some more commands later. --- .../Scripting/JsonStore/JsonStoreCommands.cs | 195 +++++++++++++++++++++ .../Scripting/JsonStore/JsonStoreModule.cs | 41 ++++- .../Scripting/JsonStore/JsonStoreScriptModule.cs | 41 ++++- 3 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs new file mode 100644 index 0000000..d4b19dd --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs @@ -0,0 +1,195 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Mono.Addins; + +using System; +using System.Reflection; +using System.Threading; +using System.Text; +using System.Net; +using System.Net.Sockets; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace OpenSim.Region.OptionalModules.Scripting.JsonStore +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreCommandsModule")] + + public class JsonStoreCommandsModule : INonSharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfig m_config = null; + private bool m_enabled = false; + + private Scene m_scene = null; + //private IJsonStoreModule m_store; + private JsonStoreModule m_store; + +#region Region Module interface + + // ----------------------------------------------------------------- + /// + /// Name of this shared module is it's class name + /// + // ----------------------------------------------------------------- + public string Name + { + get { return this.GetType().Name; } + } + + // ----------------------------------------------------------------- + /// + /// Initialise this shared module + /// + /// this region is getting initialised + /// nini config, we are not using this + // ----------------------------------------------------------------- + public void Initialise(IConfigSource config) + { + try + { + if ((m_config = config.Configs["JsonStore"]) == null) + { + // There is no configuration, the module is disabled + // m_log.InfoFormat("[JsonStore] no configuration info"); + return; + } + + m_enabled = m_config.GetBoolean("Enabled", m_enabled); + } + catch (Exception e) + { + m_log.Error("[JsonStore]: initialization error: {0}", e); + return; + } + + if (m_enabled) + m_log.DebugFormat("[JsonStore]: module is enabled"); + } + + // ----------------------------------------------------------------- + /// + /// everything is loaded, perform post load configuration + /// + // ----------------------------------------------------------------- + public void PostInitialise() + { + } + + // ----------------------------------------------------------------- + /// + /// Nothing to do on close + /// + // ----------------------------------------------------------------- + public void Close() + { + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void AddRegion(Scene scene) + { + if (m_enabled) + { + m_scene = scene; + + } + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void RemoveRegion(Scene scene) + { + // need to remove all references to the scene in the subscription + // list to enable full garbage collection of the scene object + } + + // ----------------------------------------------------------------- + /// + /// Called when all modules have been added for a region. This is + /// where we hook up events + /// + // ----------------------------------------------------------------- + public void RegionLoaded(Scene scene) + { + if (m_enabled) + { + m_scene = scene; + + m_store = (JsonStoreModule) m_scene.RequestModuleInterface(); + if (m_store == null) + { + m_log.ErrorFormat("[JsonStoreCommands]: JsonModule interface not defined"); + m_enabled = false; + return; + } + + scene.AddCommand("JsonStore", this, "jsonstore stats", "jsonstore stats", + "Display statistics about the state of the JsonStore module", "", + CmdStats); + } + } + + /// ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public Type ReplaceableInterface + { + get { return null; } + } + +#endregion + +#region Commands + + private void CmdStats(string module, string[] cmd) + { + if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) + return; + + JsonStoreStats stats = m_store.GetStoreStats(); + MainConsole.Instance.OutputFormat("{0}\t{1}",m_scene.RegionInfo.RegionName,stats.StoreCount); + } + +#endregion + + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs index 5fbfcc5..b502a55 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs @@ -42,7 +42,6 @@ using OpenSim.Region.Framework.Scenes; using System.Collections.Generic; using System.Text.RegularExpressions; - namespace OpenSim.Region.OptionalModules.Scripting.JsonStore { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreModule")] @@ -60,6 +59,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore private Scene m_scene = null; private Dictionary m_JsonValueStore; + private UUID m_sharedStore; #region Region Module interface @@ -140,6 +140,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore m_sharedStore = UUID.Zero; m_JsonValueStore = new Dictionary(); m_JsonValueStore.Add(m_sharedStore,new JsonStore("")); + + scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene; } } @@ -149,6 +151,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void RemoveRegion(Scene scene) { + scene.EventManager.OnObjectBeingRemovedFromScene -= EventManagerOnObjectBeingRemovedFromScene; + // need to remove all references to the scene in the subscription // list to enable full garbage collection of the scene object } @@ -161,7 +165,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void RegionLoaded(Scene scene) { - if (m_enabled) {} + if (m_enabled) + { + } } /// ----------------------------------------------------------------- @@ -175,8 +181,39 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore #endregion +#region SceneEvents + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public void EventManagerOnObjectBeingRemovedFromScene(SceneObjectGroup obj) + { + obj.ForEachPart(delegate(SceneObjectPart sop) { DestroyStore(sop.UUID); } ); + } + +#endregion + #region ScriptInvocationInteface + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public JsonStoreStats GetStoreStats() + { + JsonStoreStats stats; + + lock (m_JsonValueStore) + { + stats.StoreCount = m_JsonValueStore.Count; + } + + return stats; + } + // ----------------------------------------------------------------- /// /// diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs index 1bb5aee..9fbfb66 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs @@ -59,7 +59,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore private IScriptModuleComms m_comms; private IJsonStoreModule m_store; - + + private Dictionary> m_scriptStores = new Dictionary>(); + #region Region Module interface // ----------------------------------------------------------------- @@ -126,6 +128,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void AddRegion(Scene scene) { + scene.EventManager.OnScriptReset += HandleScriptReset; + scene.EventManager.OnRemoveScript += HandleScriptReset; } // ----------------------------------------------------------------- @@ -134,12 +138,34 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public void RemoveRegion(Scene scene) { + scene.EventManager.OnScriptReset -= HandleScriptReset; + scene.EventManager.OnRemoveScript -= HandleScriptReset; + // need to remove all references to the scene in the subscription // list to enable full garbage collection of the scene object } // ----------------------------------------------------------------- /// + /// + // ----------------------------------------------------------------- + private void HandleScriptReset(uint localID, UUID itemID) + { + HashSet stores; + + lock (m_scriptStores) + { + if (! m_scriptStores.TryGetValue(itemID, out stores)) + return; + m_scriptStores.Remove(itemID); + } + + foreach (UUID id in stores) + m_store.DestroyStore(id); + } + + // ----------------------------------------------------------------- + /// /// Called when all modules have been added for a region. This is /// where we hook up events /// @@ -250,6 +276,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore if (! m_store.CreateStore(value, ref uuid)) GenerateRuntimeError("Failed to create Json store"); + lock (m_scriptStores) + { + if (! m_scriptStores.ContainsKey(scriptID)) + m_scriptStores[scriptID] = new HashSet(); + + m_scriptStores[scriptID].Add(uuid); + } return uuid; } @@ -261,6 +294,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore [ScriptInvocation] public int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID) { + lock(m_scriptStores) + { + if (m_scriptStores.ContainsKey(scriptID)) + m_scriptStores[scriptID].Remove(storeID); + } + return m_store.DestroyStore(storeID) ? 1 : 0; } -- cgit v1.1 From 1cae3664a52fe48965954afc19804b11720c4add Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 20 Jan 2014 11:53:33 -0800 Subject: add null texture entry face check before converting legacy materials --- OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index ce2a56a..c4bc8a0 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -199,7 +199,7 @@ namespace OpenSim.Region.OptionalModules.Materials bool used = false; foreach (var face in te.FaceTextures) - if (face.MaterialID == id) + if (face != null && face.MaterialID == id) used = true; if (used) @@ -207,7 +207,7 @@ namespace OpenSim.Region.OptionalModules.Materials var newId = StoreMaterialAsAsset(part.CreatorID, material, part); foreach (var face in te.FaceTextures) - if (face.MaterialID == id) + if (face != null && face.MaterialID == id) face.MaterialID = newId; } } -- cgit v1.1 From af58631f00b95081dc99f4f75e8ec6b031b8cf2a Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 20 Jan 2014 13:57:14 -0800 Subject: rather than converting existing materials to assets, just retrieve them and make them available for viewing. Any new materials added to the scene will become assets. --- .../OptionalModules/Materials/MaterialsModule.cs | 44 ++++++---------------- 1 file changed, 12 insertions(+), 32 deletions(-) (limited to 'OpenSim/Region/OptionalModules') diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index c4bc8a0..afb788b 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -149,12 +149,10 @@ namespace OpenSim.Region.OptionalModules.Materials } /// - /// Searches the part for any legacy materials stored in DynAttrs and converts them to assets, replacing - /// the MaterialIDs in the TextureEntries for the part. - /// Deletes the legacy materials from the part as they are no longer needed. + /// Finds any legacy materials stored in DynAttrs that may exist for this part and add them to 'm_regionMaterials'. /// /// - private void ConvertLegacyMaterialsInPart(SceneObjectPart part) + private void GetLegacyStoredMaterialsInPart(SceneObjectPart part) { if (part.DynAttrs == null) return; @@ -183,10 +181,6 @@ namespace OpenSim.Region.OptionalModules.Materials if (matsArr == null) return; - var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); - if (te == null) - return; - foreach (OSD elemOsd in matsArr) { if (elemOsd != null && elemOsd is OSDMap) @@ -194,32 +188,18 @@ namespace OpenSim.Region.OptionalModules.Materials OSDMap matMap = elemOsd as OSDMap; if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) { - UUID id = matMap["ID"].AsUUID(); - OSDMap material = (OSDMap)matMap["Material"]; - bool used = false; - - foreach (var face in te.FaceTextures) - if (face != null && face.MaterialID == id) - used = true; - - if (used) - { // store legacy material in new asset format, and update the part texture entry with the new hashed UUID - - var newId = StoreMaterialAsAsset(part.CreatorID, material, part); - foreach (var face in te.FaceTextures) - if (face != null && face.MaterialID == id) - face.MaterialID = newId; + try + { + lock (m_regionMaterials) + m_regionMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; + } + catch (Exception e) + { + m_log.Warn("[Materials]: exception decoding persisted legacy material: " + e.ToString()); } } } } - - part.Shape.TextureEntry = te.GetBytes(); - part.ParentGroup.HasGroupChanged = true; - part.ScheduleFullUpdate(); - - lock (part.DynAttrs) - part.DynAttrs.RemoveStore("OpenSim", "Materials"); } /// @@ -230,12 +210,12 @@ namespace OpenSim.Region.OptionalModules.Materials if (part.Shape == null) return; - ConvertLegacyMaterialsInPart(part); - var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); if (te == null) return; + GetLegacyStoredMaterialsInPart(part); + GetStoredMaterialInFace(part, te.DefaultTexture); foreach (Primitive.TextureEntryFace face in te.FaceTextures) -- cgit v1.1