diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetHandlers.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetHandlers.cs index 11a4e83c7a..21f999bec5 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetHandlers.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetHandlers.cs @@ -26,21 +26,12 @@ */ using System; -using System.Collections; using System.Collections.Generic; using System.Net; -using System.Reflection; -using System.Text; -using log4net; -using Nini.Config; -using Mono.Addins; using OpenMetaverse; using OpenMetaverse.StructuredData; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using Caps=OpenSim.Framework.Capabilities.Caps; namespace OpenSim.Region.ClientStack.Linden { @@ -185,7 +176,7 @@ namespace OpenSim.Region.ClientStack.Linden Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket, bool checkEstate, int godLevel, bool limitedToEstate) { - osUTF8 sb = new osUTF8(512); + osUTF8 sb = new(512); LLSDxmlEncode2.AddMap("instantmessage", sb); LLSDxmlEncode2.AddMap("message_params", sb); //messageParams LLSDxmlEncode2.AddElem("type", dialog, sb); @@ -346,7 +337,7 @@ namespace OpenSim.Region.ClientStack.Linden public void PlacesQueryReply(UUID avatarID, UUID queryID, UUID transactionID, PlacesReplyData[] replyDataArray) { - osUTF8 sb = new osUTF8(256); + osUTF8 sb = new(256); LLSDxmlEncode2.AddMap(sb); LLSDxmlEncode2.AddElem("message", "PlacesReplyMessage", sb); LLSDxmlEncode2.AddMap("QueryData[]", sb); LLSDxmlEncode2.AddArray(sb); @@ -476,7 +467,7 @@ namespace OpenSim.Region.ClientStack.Linden public static string KeepAliveEvent() { - osUTF8 sb = new osUTF8(256); + osUTF8 sb = new(256); LLSDxmlEncode2.AddMap(sb); LLSDxmlEncode2.AddElem("message", "FAKEEVENT", sb); LLSDxmlEncode2.AddMap("body", sb); @@ -485,9 +476,63 @@ namespace OpenSim.Region.ClientStack.Linden return sb.ToString(); } + public void SendLargeGenericMessage(UUID avatarID, UUID? transationID, UUID? sessionID, + string method, UUID invoice, List message) + { + osUTF8 sb = StartEvent("LargeGenericMessage"); + LLSDxmlEncode2.AddArrayAndMap("AgentData", sb); + LLSDxmlEncode2.AddElem("AgentID", avatarID, sb); + if (transationID.HasValue) + LLSDxmlEncode2.AddElem("TransactionID", transationID.Value, sb); + if (sessionID.HasValue) + LLSDxmlEncode2.AddElem("SessionID", sessionID.Value, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + LLSDxmlEncode2.AddArrayAndMap("MethodData", sb); + LLSDxmlEncode2.AddElem("Method", method, sb); + LLSDxmlEncode2.AddElem("Invoice", invoice, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + LLSDxmlEncode2.AddArrayAndMap("ParamList", sb); + foreach (string s in message) + LLSDxmlEncode2.AddElem("Parameter", s, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + Enqueue(EndEventToBytes(sb), avatarID); + } + + public void SendLargeGenericMessage(UUID avatarID, UUID? transationID, UUID? sessionID, + string method, UUID invoice, List message) + { + osUTF8 sb = StartEvent("LargeGenericMessage"); + LLSDxmlEncode2.AddArrayAndMap("AgentData", sb); + LLSDxmlEncode2.AddElem("AgentID", avatarID, sb); + if (transationID.HasValue) + LLSDxmlEncode2.AddElem("TransactionID", transationID.Value, sb); + if (sessionID.HasValue) + LLSDxmlEncode2.AddElem("SessionID", sessionID.Value, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + LLSDxmlEncode2.AddArrayAndMap("MethodData", sb); + LLSDxmlEncode2.AddElem("Method", method, sb); + LLSDxmlEncode2.AddElem("Invoice", invoice, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + LLSDxmlEncode2.AddArrayAndMap("ParamList", sb); + foreach (byte[] b in message) + { + LLSDxmlEncode2.AddLLSD("Parameter", sb); + sb.Append(b); + LLSDxmlEncode2.AddLLSD("", sb); + } + LLSDxmlEncode2.AddEndMapAndArray(sb); + + Enqueue(EndEventToBytes(sb), avatarID); + } + public byte[] BuildEvent(string eventName, OSD eventBody) { - OSDMap llsdEvent = new OSDMap(2); + OSDMap llsdEvent = new(2); llsdEvent.Add("message", new OSDString(eventName)); llsdEvent.Add("body", eventBody); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index e3aa8c28d6..6256d233c4 100755 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -27,6 +27,8 @@ using System; using System.Collections.Generic; +using System.Drawing; +using System.Linq; using System.Net; using System.Reflection; using System.Runtime; @@ -4767,6 +4769,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP List compressedUpdates = null; List terseUpdates = null; List ObjectAnimationUpdates = null; + List needMaterials = null; // Check to see if this is a flush if (maxUpdatesBytes <= 0) @@ -4821,6 +4824,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP useCompressUpdate = false; bool istree = false; + bool hasMaterialOverride = false; if (update.Entity is SceneObjectPart part) { @@ -4965,6 +4969,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP useCompressUpdate = grp.IsViewerCachable; istree = (part.Shape.PCode == (byte)PCode.Grass || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Tree); + if(!istree && part.Shape.RenderMaterials is not null && + part.Shape.ReflectionProbe is null && + part.Shape.RenderMaterials.overrides is not null && + part.Shape.RenderMaterials.overrides.Length > 0) + hasMaterialOverride = true; } else if (update.Entity is ScenePresence presence) { @@ -5076,6 +5085,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP } objectUpdates.Add(update); } + if(hasMaterialOverride) + { + needMaterials ??= new List(16); + needMaterials.Add((SceneObjectPart)update.Entity); + } } } @@ -5090,8 +5104,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; timeDilation = Utils.FloatZeroOneToushort(m_scene.TimeDilation); - - if(objectUpdates is not null) + if (objectUpdates is not null) { //List tau = new List(30); @@ -5183,71 +5196,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - /* no zero encode compressed updates - if(compressedUpdates != null) - { - List tau = new List(30); - - UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); - byte[] data = buf.Data; - - Buffer.BlockCopy(CompressedObjectHeader, 0, data , 0, 7); - - Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, data, 7); // 15 - Utils.UInt16ToBytes(timeDilation, data, 15); // 17 - - int countposition = 17; // blocks count position - int pos = 18; - - int lastpos = 0; - - int count = 0; - foreach (EntityUpdate eu in compressedUpdates) - { - SceneObjectPart sop = (SceneObjectPart)eu.Entity; - if (sop.ParentGroup is null || sop.ParentGroup.IsDeleted) - continue; - lastpos = pos; - CreateCompressedUpdateBlock(sop, mysp, data, ref pos); - if (pos < LLUDPServer.MAXPAYLOAD) - { - tau.Add(eu); - ++count; - } - else - { - // we need more packets - UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); - Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same - - buf.Data[countposition] = (byte)count; - - buf.DataLength = lastpos; - m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, - delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); - - buf = newbuf; - data = buf.Data; - - pos = 18; - // im lazy now, just do last again - CreateCompressedUpdateBlock(sop, mysp, data, ref pos); - tau = new List(30); - tau.Add(eu); - count = 1; - } - } - - if (count > 0) - { - buf.Data[countposition] = (byte)count; - buf.DataLength = pos; - m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, - delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); - } - } - */ - if (compressedUpdates is not null) { //List tau = new List(30); @@ -5545,6 +5493,70 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + IEventQueue eq = Scene.RequestModuleInterface(); + if (needMaterials is not null && eq is not null) + { + Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out uint regionX, out uint regionY); + foreach (SceneObjectPart sop in needMaterials) + { + Primitive.RenderMaterials.RenderMaterialOverrideEntry[] overrides = sop.Shape.RenderMaterials.overrides; + /* + osUTF8 sbinner = LLSDxmlEncode2.Start(); + LLSDxmlEncode2.AddArray(sbinner); + LLSDxmlEncode2.AddMap(sbinner); + LLSDxmlEncode2.AddElem("object_id", sop.UUID, sbinner); + LLSDxmlEncode2.AddElem("region_handle_low", (int)regionX, sbinner); + LLSDxmlEncode2.AddElem("region_handle_high", (int)regionY, sbinner); + LLSDxmlEncode2.AddArray("sides", sbinner); + foreach (Primitive.RenderMaterials.RenderMaterialOverrideEntry ovr in overrides) + LLSDxmlEncode2.AddElem(ovr.te_index, sbinner); + LLSDxmlEncode2.AddEndArray(sbinner); + LLSDxmlEncode2.AddArray("gltf_json", sbinner); + foreach (Primitive.RenderMaterials.RenderMaterialOverrideEntry ovr in overrides) + { + LLSDxmlEncode2.AddElem(ovr.data, sbinner); + } + LLSDxmlEncode2.AddEndArray(sbinner); + LLSDxmlEncode2.AddEndMapAndArray(sbinner); + LLSDxmlEncode2.AddEnd(sbinner); + */ + OSDMap data = new OSDMap(); + data["object_id"] = sop.UUID; + //data["region_handle_low"]= (int)regionX; + //data["region_handle_high"]= (int)regionY; + OSDArray sides = new OSDArray(); + foreach (Primitive.RenderMaterials.RenderMaterialOverrideEntry ovr in overrides) + sides.Add(ovr.te_index); + data["sides"] = sides; + + OSDArray gltf = new OSDArray(); + foreach (Primitive.RenderMaterials.RenderMaterialOverrideEntry ovr in overrides) + gltf.Add(ovr.data); + data["gltf_json"] = gltf; + + string inner = OSDParser.SerializeLLSDNotationFull(data); + + osUTF8 sb = eq.StartEvent("LargeGenericMessage"); + LLSDxmlEncode2.AddArrayAndMap("AgentData", sb); + LLSDxmlEncode2.AddElem("AgentID", AgentId, sb); + //LLSDxmlEncode2.AddElem("TransactionID", transationID.Value, sb); + //LLSDxmlEncode2.AddElem("SessionID", sessionID.Value, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + LLSDxmlEncode2.AddArrayAndMap("MethodData", sb); + LLSDxmlEncode2.AddElem("Method", "GLTFMaterialOverride", sb); + LLSDxmlEncode2.AddElem("Invoice", UUID.Zero, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + LLSDxmlEncode2.AddArrayAndMap("ParamList", sb); + //LLSDxmlEncode2.AddElem("Parameter", sbinner, sb); + LLSDxmlEncode2.AddElem("Parameter", inner, sb); + LLSDxmlEncode2.AddEndMapAndArray(sb); + + //OSUTF8Cached.Release(sbinner); + eq.Enqueue(eq.EndEventToBytes(sb), AgentId); + } + } #endregion Packet Sending #region Handle deleted objects diff --git a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs index 44f2bd9eeb..e481a9d249 100644 --- a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs +++ b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs @@ -109,6 +109,10 @@ namespace OpenSim.Region.Framework.Interfaces void SendBulkUpdateInventoryItem(InventoryItemBase item, UUID avatarID, UUID? transationID = null); osUTF8 StartEvent(string eventName); osUTF8 StartEvent(string eventName, int cap); + void SendLargeGenericMessage(UUID avatarID, UUID? transationID, UUID? sessionID, + string method, UUID invoice, List message); + void SendLargeGenericMessage(UUID avatarID, UUID? transationID, UUID? sessionID, + string method, UUID invoice, List message); byte[] EndEventToBytes(osUTF8 sb); } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 55fa928e73..23f90a79c7 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -5287,7 +5287,7 @@ namespace OpenSim.Region.Framework.Scenes linknumber -= (m_parts.Count + 1); lock (m_sittingAvatars) { - if (linknumber >= 0 && linknumber < m_sittingAvatars.Count) + if (linknumber < m_sittingAvatars.Count && linknumber >= 0) return m_sittingAvatars[linknumber]; } return null; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 9b0eeb7869..ee00032f3a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -5755,7 +5755,7 @@ namespace OpenSim.Region.Framework.Scenes int pos = 2; while(--count >= 0) { - UUID id = new UUID(data, pos); + UUID id = new(data, pos); if(id.IsZero()) break; pos += 16; diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index adb248e3f5..77a2aec34e 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -36,6 +36,8 @@ using Mono.Addins; using Nini.Config; using OpenMetaverse; +using static OpenMetaverse.Primitive; +using static OpenMetaverse.Primitive.RenderMaterials; using OpenMetaverse.StructuredData; using OpenSim.Framework; @@ -61,23 +63,23 @@ namespace OpenSim.Region.OptionalModules.Materials private Scene m_scene = null; private bool m_enabled = false; private int m_maxMaterialsPerTransaction = 50; - private object materialslock = new object(); + private readonly object materialslock = new(); - public Dictionary m_Materials = new Dictionary(); - public Dictionary m_MaterialsRefCount = new Dictionary(); + public Dictionary m_Materials = new(); + public Dictionary m_MaterialsRefCount = new(); - private Dictionary m_changed = new Dictionary(); - private Queue delayedDelete = new Queue(); + private readonly Dictionary m_changed = new(); + private readonly Queue delayedDelete = new(); private bool m_storeBusy; - private static byte[] GetPutEmptyResponseBytes = osUTF8.GetASCIIBytes("ZippedeNqLZgCCWAAChQC5"); + private static readonly byte[] GetPutEmptyResponseBytes = osUTF8.GetASCIIBytes("ZippedeNqLZgCCWAAChQC5"); public void Initialise(IConfigSource source) { m_enabled = true; // default is enabled IConfig config = source.Configs["Materials"]; - if (config != null) + if (config is not null) { m_enabled = config.GetBoolean("enable_materials", m_enabled); m_maxMaterialsPerTransaction = config.GetInt("MaxMaterialsPerTransaction", m_maxMaterialsPerTransaction); @@ -124,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Materials m_cache = scene.RequestModuleInterface(); ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface(); - if (featuresModule != null) + if (featuresModule is not null) { featuresModule.AddOpenSimExtraFeature("MaxMaterialsPerTransaction", m_maxMaterialsPerTransaction); featuresModule.AddOpenSimExtraFeature("RenderMaterialsCapability", 3.0f); @@ -217,15 +219,17 @@ namespace OpenSim.Region.OptionalModules.Materials private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) { foreach (var part in obj.Parts) - if (part != null) + { + if (part is not null) GetStoredMaterialsInPart(part); + } } private void EventManager_OnObjectDeleteFromScene(SceneObjectGroup obj) { foreach (var part in obj.Parts) { - if (part != null) + if (part is not null) RemoveMaterialsInPart(part); } } @@ -271,12 +275,11 @@ namespace OpenSim.Region.OptionalModules.Materials /// private bool GetLegacyStoredMaterialsInPart(SceneObjectPart part) { - if (part.DynAttrs == null) + if (part.DynAttrs is null) return false; OSD OSMaterials = null; - OSDArray matsArr = null; - + OSDArray matsArr; bool partchanged = false; lock (part.DynAttrs) @@ -284,8 +287,7 @@ namespace OpenSim.Region.OptionalModules.Materials if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) { OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); - - if (materialsStore == null) + if (materialsStore is null) return false; materialsStore.TryGetValue("Materials", out OSMaterials); @@ -293,42 +295,37 @@ namespace OpenSim.Region.OptionalModules.Materials partchanged = true; } - if (OSMaterials != null && OSMaterials is OSDArray) - matsArr = OSMaterials as OSDArray; - else + if (OSMaterials is not OSDArray) return partchanged; + matsArr = (OSDArray)OSMaterials; } - if (matsArr == null) + if (matsArr is null) return partchanged; foreach (OSD elemOsd in matsArr) { - if (elemOsd != null && elemOsd is OSDMap) + if (elemOsd is OSDMap matMap) { - OSDMap matMap = elemOsd as OSDMap; - OSD OSDID; - OSD OSDMaterial; - if (matMap.TryGetValue("ID", out OSDID) && matMap.TryGetValue("Material", out OSDMaterial) && OSDMaterial is OSDMap) + if (matMap.TryGetValue("ID", out OSD OSDID) && + matMap.TryGetValue("Material", out OSD OSDMaterial) && OSDMaterial is OSDMap theMatMap) { try { lock (materialslock) { UUID id = OSDID.AsUUID(); - if(m_Materials.ContainsKey(id)) + if (m_Materials.ContainsKey(id)) continue; - OSDMap theMatMap = (OSDMap)OSDMaterial; - FaceMaterial fmat = new FaceMaterial(theMatMap); - - if(fmat == null || - ( fmat.DiffuseAlphaMode == 1 + FaceMaterial fmat = new(theMatMap); + if (fmat is null || + (fmat.DiffuseAlphaMode == 1 && fmat.NormalMapID.IsZero() && fmat.SpecularMapID.IsZero())) continue; - fmat.ID = id; + fmat.ID = id; m_Materials[id] = fmat; m_MaterialsRefCount[id] = 0; } @@ -348,18 +345,17 @@ namespace OpenSim.Region.OptionalModules.Materials /// private void GetStoredMaterialsInPart(SceneObjectPart part) { - if (part.Shape == null) + if (part.Shape is null) return; - bool partchanged = false; - bool facechanged = false; var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); - if (te == null) + if (te is null) return; - partchanged = GetLegacyStoredMaterialsInPart(part); + bool partchanged = GetLegacyStoredMaterialsInPart(part); + bool facechanged = false; - if (te.DefaultTexture != null) + if (te.DefaultTexture is not null) facechanged = GetStoredMaterialInFace(part, te.DefaultTexture); else m_log.WarnFormat( @@ -368,7 +364,7 @@ namespace OpenSim.Region.OptionalModules.Materials foreach (Primitive.TextureEntryFace face in te.FaceTextures) { - if (face != null) + if (face is not null) facechanged |= GetStoredMaterialInFace(part, face); } @@ -377,7 +373,7 @@ namespace OpenSim.Region.OptionalModules.Materials if(facechanged || partchanged) { - if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) + if (part.ParentGroup is not null && !part.ParentGroup.IsDeleted) part.ParentGroup.HasGroupChanged = true; } } @@ -401,7 +397,7 @@ namespace OpenSim.Region.OptionalModules.Materials } AssetBase matAsset = m_scene.AssetService.Get(id.ToString()); - if (matAsset == null || matAsset.Data == null || matAsset.Data.Length == 0 ) + if (matAsset is null || matAsset.Data is null || matAsset.Data.Length == 0 ) { // grid may just be down... return false; @@ -420,9 +416,8 @@ namespace OpenSim.Region.OptionalModules.Materials return false; } - FaceMaterial fmat = new FaceMaterial(mat); - - if(fmat == null || + FaceMaterial fmat = new(mat); + if(fmat is null || (fmat.DiffuseAlphaMode == 1 && fmat.NormalMapID.IsZero() && fmat.SpecularMapID.IsZero())) @@ -448,19 +443,19 @@ namespace OpenSim.Region.OptionalModules.Materials private void RemoveMaterialsInPart(SceneObjectPart part) { - if (part.Shape == null) + if (part.Shape is null) return; var te = new Primitive.TextureEntry(part.Shape.TextureEntry, 0, part.Shape.TextureEntry.Length); - if (te == null) + if (te is null) return; - if (te.DefaultTexture != null) + if (te.DefaultTexture is not null) RemoveMaterialInFace(te.DefaultTexture); foreach (Primitive.TextureEntryFace face in te.FaceTextures) { - if(face != null) + if(face is not null) RemoveMaterialInFace(face); } } @@ -495,34 +490,33 @@ namespace OpenSim.Region.OptionalModules.Materials return; } - OSDArray respArr = new OSDArray(); - OSD tmpOSD; + OSDArray respArr = new(); - if (req.TryGetValue("Zipped", out tmpOSD)) + if (req.TryGetValue("Zipped", out OSD tmpOSD)) { - OSD osd = null; - + OSD osd; byte[] inBytes = tmpOSD.AsBinary(); try { osd = ZDecompressBytesToOsd(inBytes); - - if (osd != null && osd is OSDArray) + if (osd is OSDArray OSDArrayosd) { - foreach (OSD elem in (OSDArray)osd) + foreach (OSD elem in OSDArrayosd) { try { - UUID id = new UUID(elem.AsBinary(), 0); + UUID id = new(elem.AsBinary(), 0); lock (materialslock) { if (m_Materials.ContainsKey(id)) { - OSDMap matMap = new OSDMap(); - matMap["ID"] = OSD.FromBinary(id.GetBytes()); - matMap["Material"] = m_Materials[id].toOSD(); + OSDMap matMap = new() + { + ["ID"] = OSD.FromBinary(id.GetBytes()), + ["Material"] = m_Materials[id].toOSD() + }; respArr.Add(matMap); } else @@ -552,8 +546,10 @@ namespace OpenSim.Region.OptionalModules.Materials } } - OSDMap resp = new OSDMap(); - resp["Zipped"] = ZCompressOSD(respArr, false); + OSDMap resp = new() + { + ["Zipped"] = ZCompressOSD(respArr, false) + }; response.RawBuffer = Encoding.UTF8.GetBytes(OSDParser.SerializeLLSDXmlString(resp)); //m_log.Debug("[Materials]: cap request: " + request); @@ -574,22 +570,19 @@ namespace OpenSim.Region.OptionalModules.Materials return; } - OSD tmpOSD; - if (req.TryGetValue("Zipped", out tmpOSD)) + if (req.TryGetValue("Zipped", out OSD tmpOSD)) { try { byte[] inBytes = tmpOSD.AsBinary(); OSD osd = ZDecompressBytesToOsd(inBytes); - if (osd != null && osd is OSDMap) + if (osd is OSDMap materialsFromViewer) { - OSDMap materialsFromViewer = osd as OSDMap; - if (materialsFromViewer.TryGetValue("FullMaterialsPerFace", out tmpOSD) && (tmpOSD is OSDArray)) { - Dictionary parts = new Dictionary(); - HashSet errorReported = new HashSet(); + Dictionary parts = new(); + HashSet errorReported = new(); OSDArray matsArr = tmpOSD as OSDArray; try { @@ -607,7 +600,7 @@ namespace OpenSim.Region.OptionalModules.Materials } SceneObjectPart sop = m_scene.GetSceneObjectPart(primLocalID); - if (sop == null) + if (sop is null) { m_log.WarnFormat("[Materials]: SOP not found for localId: {0}", primLocalID.ToString()); continue; @@ -634,8 +627,8 @@ namespace OpenSim.Region.OptionalModules.Materials continue; } - Primitive.TextureEntry te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); - if (te == null) + Primitive.TextureEntry te = new(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); + if (te is null) { m_log.WarnFormat("[Materials]: Error in TextureEntry for SOP {0} {1}", sop.Name, sop.UUID); continue; @@ -652,12 +645,12 @@ namespace OpenSim.Region.OptionalModules.Materials else faceEntry = te.DefaultTexture; - if (faceEntry == null) + if (faceEntry is null) continue; UUID id; FaceMaterial newFaceMat = null; - if (mat == null) + if (mat is null) { // This happens then the user removes a material from a prim id = UUID.Zero; @@ -665,7 +658,7 @@ namespace OpenSim.Region.OptionalModules.Materials else { newFaceMat = new FaceMaterial(mat); - if(newFaceMat.DiffuseAlphaMode == 1 + if (newFaceMat.DiffuseAlphaMode == 1 && newFaceMat.NormalMapID.IsZero() && newFaceMat.SpecularMapID.IsZero()) id = UUID.Zero; @@ -678,10 +671,10 @@ namespace OpenSim.Region.OptionalModules.Materials oldid = faceEntry.MaterialID; - if(oldid == id) + if (oldid == id) continue; - if (faceEntry != null) + if (faceEntry is not null) { faceEntry.MaterialID = id; //m_log.DebugFormat("[Materials]: in \"{0}\" {1}, setting material ID for face {2} to {3}", sop.Name, sop.UUID, face, id); @@ -689,12 +682,12 @@ namespace OpenSim.Region.OptionalModules.Materials sop.Shape.TextureEntry = te.GetBytes(9); } - if(!oldid.IsZero()) + if (!oldid.IsZero()) RemoveMaterial(oldid); - lock(materialslock) + lock (materialslock) { - if(!id.IsZero()) + if (id.IsNotZero()) { if (m_Materials.ContainsKey(id)) m_MaterialsRefCount[id]++; @@ -707,13 +700,12 @@ namespace OpenSim.Region.OptionalModules.Materials } } - if(!parts.ContainsKey(primLocalID)) - parts[primLocalID] = sop; + parts[primLocalID] = sop; } - foreach(SceneObjectPart sop in parts.Values) + foreach (SceneObjectPart sop in parts.Values) { - if (sop.ParentGroup != null && !sop.ParentGroup.IsDeleted) + if (sop.ParentGroup is not null && !sop.ParentGroup.IsDeleted) { sop.TriggerScriptChangedEvent(Changed.TEXTURE); sop.ScheduleFullUpdate(); @@ -749,27 +741,26 @@ namespace OpenSim.Region.OptionalModules.Materials private AssetBase MakeAsset(FaceMaterial fm, bool local) { - // this are not true assets, should had never been... - AssetBase asset = null; byte[] data = fm.toLLSDxml(); - - asset = new AssetBase(fm.ID, "llmaterial", (sbyte)OpenSimAssetType.Material, "00000000-0000-0000-0000-000000000000"); - asset.Data = data; - asset.Local = local; + AssetBase asset = new(fm.ID, "llmaterial", (sbyte)OpenSimAssetType.Material, "00000000-0000-0000-0000-000000000000") + { + Data = data, + Local = local + }; return asset; } private byte[] CacheGet = null; - private object CacheGetLock = new object(); + private readonly object CacheGetLock = new(); private double CacheGetTime = 0; public void RenderMaterialsGetCap(IOSHttpRequest request, IOSHttpResponse response) { lock(CacheGetLock) { - OSDArray allOsd = new OSDArray(); + OSDArray allOsd = new(); double now = Util.GetTimeStamp(); - if(CacheGet == null || now - CacheGetTime > 30) + if(CacheGet is null || now - CacheGetTime > 30) { CacheGetTime = now; @@ -777,7 +768,7 @@ namespace OpenSim.Region.OptionalModules.Materials { foreach (KeyValuePair kvp in m_Materials) { - OSDMap matMap = new OSDMap + OSDMap matMap = new() { ["ID"] = OSD.FromBinary(kvp.Key.GetBytes()), ["Material"] = kvp.Value.toOSD() @@ -786,7 +777,7 @@ namespace OpenSim.Region.OptionalModules.Materials } } - OSDMap resp = new OSDMap + OSDMap resp = new() { ["Zipped"] = ZCompressOSD(allOsd, false) }; @@ -811,11 +802,8 @@ namespace OpenSim.Region.OptionalModules.Materials public static OSD ZCompressOSD(OSD inOsd, bool useHeader) { - OSD osd = null; - byte[] data = OSDParser.SerializeLLSDBinary(inOsd, useHeader); - - using (MemoryStream msSinkCompressed = new MemoryStream()) + using (MemoryStream msSinkCompressed = new()) { using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) @@ -824,42 +812,34 @@ namespace OpenSim.Region.OptionalModules.Materials } msSinkCompressed.Seek(0L, SeekOrigin.Begin); - osd = OSD.FromBinary(msSinkCompressed.ToArray()); + return OSD.FromBinary(msSinkCompressed.ToArray()); } - - return osd; } public static OSD ZDecompressBytesToOsd(byte[] input) { - OSD osd = null; - - using (MemoryStream msSinkUnCompressed = new MemoryStream()) + using (MemoryStream msSinkUnCompressed = new()) { - using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) + using (Ionic.Zlib.ZlibStream zOut = new(msSinkUnCompressed, CompressionMode.Decompress, true)) { zOut.Write(input, 0, input.Length); } msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); - osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); + return OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); } - - return osd; } public FaceMaterial GetMaterial(UUID ID) { - FaceMaterial fm = null; - if(m_Materials.TryGetValue(ID, out fm)) + if(m_Materials.TryGetValue(ID, out FaceMaterial fm)) return fm; return null; } public FaceMaterial GetMaterialCopy(UUID ID) { - FaceMaterial fm = null; - if(m_Materials.TryGetValue(ID, out fm)) + if(m_Materials.TryGetValue(ID, out FaceMaterial fm)) return new FaceMaterial(fm); return null; } @@ -915,10 +895,10 @@ namespace OpenSim.Region.OptionalModules.Materials httpResponse.StatusCode = (int)HttpStatusCode.NotFound; return; } - OSDArray req; + try { - req = (OSDArray)OSDParser.DeserializeLLSDXml(httpRequest.InputStream); + OSDArray req = (OSDArray)OSDParser.DeserializeLLSDXml(httpRequest.InputStream); httpRequest.InputStream.Dispose(); OSD tmp; @@ -940,86 +920,195 @@ namespace OpenSim.Region.OptionalModules.Materials if (pbs is null) continue; + if (!m_scene.Permissions.CanEditObject(sop.UUID, agentID)) + continue; + if (!map.TryGetValue("side", out tmp)) continue; int side = tmp.AsInteger(); - UUID assetID; - if (map.TryGetValue("asset_id", out tmp)) - assetID = tmp.AsUUID(); - else - assetID = UUID.Zero; - + string overridedata; if (map.TryGetValue("gltf_json", out tmp)) + overridedata = tmp.AsString().TrimEnd('\n'); + else + overridedata = string.Empty; + + if (map.TryGetValue("asset_id", out tmp)) { - string assetdata = tmp.AsString(); - if (!string.IsNullOrEmpty(assetdata)) + UUID assetID = tmp.AsUUID(); + if (assetID.IsNotZero()) { - if (pbs.RenderMaterials is not null) + if (pbs.RenderMaterials is null) { - int sideIndex = 0; - while (sideIndex < pbs.RenderMaterials.entries.Length) + var entries = new Primitive.RenderMaterials.RenderMaterialEntry[1]; + entries[0].te_index = (byte)side; + entries[0].id = assetID; + pbs.RenderMaterials = new Primitive.RenderMaterials { entries = entries }; + } + else + { + if (pbs.RenderMaterials.entries is null) { - if (pbs.RenderMaterials.entries[sideIndex].te_index == side) - break; - sideIndex++; + var entries = new Primitive.RenderMaterials.RenderMaterialEntry[1]; + entries[0].te_index = (byte)side; + entries[0].id = assetID; + pbs.RenderMaterials.entries = entries; } - if (sideIndex < pbs.RenderMaterials.entries.Length) + else { - - - changedSOPs.Add(sop); + int indx = 0; + while (indx < pbs.RenderMaterials.entries.Length) + { + if (pbs.RenderMaterials.entries[indx].te_index == side) + { + pbs.RenderMaterials.entries[indx].id = assetID; + break; + } + indx++; + } + if (indx == pbs.RenderMaterials.entries.Length) + { + Array.Resize(ref pbs.RenderMaterials.entries, indx + 1); + pbs.RenderMaterials.entries[indx].te_index = (byte)side; + pbs.RenderMaterials.entries[indx].id = assetID; + } } } + if (string.IsNullOrEmpty(overridedata)) + RemoveMaterialOverride(ref pbs.RenderMaterials.overrides, side); + else + AddMaterialOverride(ref pbs.RenderMaterials.overrides, overridedata, side); + + changedSOPs.Add(sop); + } + else if(pbs.RenderMaterials is not null) + { + bool changed = RemoveMaterialEntry(ref pbs.RenderMaterials.entries, side); + changed |= RemoveMaterialOverride(ref pbs.RenderMaterials.overrides, side); + + if(pbs.RenderMaterials.entries is null && pbs.RenderMaterials.overrides is null) + pbs.RenderMaterials = null; + if(changed) + changedSOPs.Add(sop); } } - - if (assetID.IsNotZero()) + else if (pbs.RenderMaterials is not null) { - if (pbs.RenderMaterials is null) + if (string.IsNullOrEmpty(overridedata)) { - var entries = new Primitive.RenderMaterials.RenderMaterialEntry[1]; - entries[0].te_index = (byte)side; - entries[0].id = assetID; - pbs.RenderMaterials = new Primitive.RenderMaterials - { - entries = entries - }; + } else { - int i = 0; - while(i < pbs.RenderMaterials.entries.Length) - { - if (pbs.RenderMaterials.entries[i].te_index == side) - { - pbs.RenderMaterials.entries[i].id = assetID; - break; - } - i++; - } - if (i == pbs.RenderMaterials.entries.Length) - { - Array.Resize(ref pbs.RenderMaterials.entries, i + 1); - pbs.RenderMaterials.entries[i].te_index = (byte)side; - pbs.RenderMaterials.entries[i].id = assetID; - } + if(AddMaterialOverride(ref pbs.RenderMaterials.overrides, overridedata, side)) + changedSOPs.Add(sop); } - changedSOPs.Add(sop); } } - foreach(SceneObjectPart sop in changedSOPs) + foreach (SceneObjectPart sop in changedSOPs) { sop.ParentGroup.HasGroupChanged = true; sop.ScheduleFullUpdate(); } + httpResponse.RawBuffer = XMLkeyMaterialSucess; httpResponse.StatusCode = (int)HttpStatusCode.OK; } catch { httpResponse.StatusCode = (int)HttpStatusCode.BadRequest; + httpResponse.RawBuffer = XMLkeyMaterialFail; } } + + public static readonly byte[] XMLkeyMaterialSucess = osUTF8.GetASCIIBytes("success1\r\n"); + public static readonly byte[] XMLkeyMaterialFail = osUTF8.GetASCIIBytes("success0\r\n"); + private static bool RemoveMaterialEntry(ref RenderMaterialEntry[] entries, int side) + { + if (entries is null || entries.Length == 0) + return false; + + int indx = 0; + while (entries[indx].te_index != side && indx < entries.Length) + indx++; + + if (indx >= entries.Length) + return false; + + if (entries.Length == 1) + entries = null; + else + { + var newentries = new Primitive.RenderMaterials.RenderMaterialEntry[entries.Length - 1]; + if (indx > 0) + Array.Copy(entries, newentries, indx); + int left = newentries.Length - indx; + if (left > 0) + Array.Copy(entries, indx + 1, newentries, indx, left); + entries = newentries; + } + return true; + } + + private static bool RemoveMaterialOverride(ref RenderMaterialOverrideEntry[] overrides, int side) + { + if (overrides is null || overrides.Length == 0) + return false; + + int indx = 0; + while(overrides[indx].te_index != side && indx < overrides.Length) + indx++; + + if (indx >= overrides.Length) + return false; + + if (overrides.Length == 1) + overrides = null; + else + { + var entries = new Primitive.RenderMaterials.RenderMaterialOverrideEntry[overrides.Length - 1]; + if (indx > 0) + Array.Copy(overrides, entries, indx); + int left = entries.Length - indx; + if (left > 0) + Array.Copy(overrides, indx + 1, entries, indx, left); + overrides = entries; + } + return true; + } + + private static bool AddMaterialOverride(ref RenderMaterials.RenderMaterialOverrideEntry[] overrides, string data, int side) + { + if (overrides is null) + { + var entries = new RenderMaterials.RenderMaterialOverrideEntry[1]; + entries[0].te_index = (byte)side; + entries[0].data = data; + overrides = entries; + return true; + } + + int indx = 0; + while (indx < overrides.Length) + { + if (overrides[indx].te_index == side) + { + overrides[indx].data = data; + return true; + } + indx++; + } + if (indx == overrides.Length) + { + Array.Resize(ref overrides, indx + 1); + overrides[indx].te_index = (byte)side; + if(overrides[indx].data != data) + { + overrides[indx].data = data; + return true; + } + } + return false; + } } }