From 91b76da1e2b9674b4104618e86da0e2b126c6a7c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 29 Aug 2022 19:42:21 +0100 Subject: [PATCH] a few more useless to unsafe sections --- .../ClientStack/Linden/UDP/LLClientView.cs | 249 ++++++++++-------- bin/OpenMetaverse.Rendering.Meshmerizer.dll | Bin 20480 -> 20480 bytes bin/OpenMetaverse.StructuredData.dll | Bin 126976 -> 126976 bytes bin/OpenMetaverse.dll | Bin 2174976 -> 2174976 bytes bin/OpenMetaverseTypes.dll | Bin 172032 -> 172032 bytes 5 files changed, 136 insertions(+), 113 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 5a934a9170..bd32ca75f4 100755 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -2290,8 +2290,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP currentPacket.ItemData[itemsSent % MAX_ITEMS_PER_PACKET] = CreateItemDataBlock(items[itemsSent++]); else { -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID); + //m_log.DebugFormat( + // "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID); OutPacket(currentPacket, ThrottleOutPacketType.Asset, false); currentPacket = null; } @@ -2299,8 +2299,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (currentPacket != null) { -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID); + //m_log.DebugFormat( + // "[LLCLIENTVIEW]: Sending inventory folder details packet to {0} for folder {1}", Name, folderID); OutPacket(currentPacket, ThrottleOutPacketType.Asset, false); } } @@ -4568,7 +4568,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP zc.Position = 7; zc.AddUInt64(m_scene.RegionInfo.RegionHandle); - zc.AddUInt16(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f)); + zc.AddUInt16(Utils.FloatZeroOneToushort(m_scene.TimeDilation)); zc.AddByte(1); // block count @@ -4592,10 +4592,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP Buffer.BlockCopy(terseUpdateHeader, 0, buf.Data, 0, 7); fixed(byte* bdata = &buf.Data[0]) { - Utils.UInt16ToBytes(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f), bdata + 15); + Utils.UInt16ToBytes(Utils.FloatZeroOneToushort(m_scene.TimeDilation), bdata + 15); bdata[17] = 1; - byte* data = bdata + 18; + byte* data = bdata + 18; if (ent is ScenePresence) { Utils.UInt64ToBytes(((ScenePresence)ent).RegionHandle, bdata + 7); @@ -4980,7 +4980,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (objectUpdateProbes == null) { - objectUpdateProbes = new List(32); + objectUpdateProbes = new List(64); maxUpdatesBytes -= 18; } objectUpdateProbes.Add(update); @@ -5128,7 +5128,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!IsActive) return; - timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); + timeDilation = Utils.FloatZeroOneToushort(m_scene.TimeDilation); if(objectUpdates != null) { @@ -5385,61 +5385,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP { UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); byte[] data = buf.Data; - Buffer.BlockCopy(ObjectUpdateCachedHeader, 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; + const int countposition = 17; // blocks count index + int pos = countposition + 1; int count = 0; EntityUpdate eu; - for (int indx = 0; indx < objectUpdateProbes.Count; ++indx) + + int indx = 0; + while (indx < objectUpdateProbes.Count) { - eu = objectUpdateProbes[indx]; - SceneObjectPart sop = (SceneObjectPart)eu.Entity; - if (sop.ParentGroup == null || sop.ParentGroup.IsDeleted) - continue; - uint primflags = m_scene.Permissions.GenerateClientFlags(sop, mysp); - if (mysp.UUID != sop.OwnerID) - primflags &= ~(uint)PrimFlags.CreateSelected; - else + unsafe { - if (sop.CreateSelected) - primflags |= (uint)PrimFlags.CreateSelected; - else - primflags &= ~(uint)PrimFlags.CreateSelected; + fixed(byte* bdata = &data[countposition + 1]) + { + byte* ptr = bdata; + while (indx < objectUpdateProbes.Count) + { + eu = objectUpdateProbes[indx++]; + SceneObjectPart sop = (SceneObjectPart)eu.Entity; + if (sop.ParentGroup == null || sop.ParentGroup.IsDeleted) + continue; + uint primflags = m_scene.Permissions.GenerateClientFlags(sop, mysp); + if (mysp.UUID.NotEqual(sop.OwnerID)) + primflags &= ~(uint)PrimFlags.CreateSelected; + else + { + if (sop.CreateSelected) + primflags |= (uint)PrimFlags.CreateSelected; + else + primflags &= ~(uint)PrimFlags.CreateSelected; + } + + Utils.UIntToBytes(sop.LocalId, ptr); ptr += 4; + Utils.UIntToBytes((uint)sop.PseudoCRC, ptr); ptr += 4; //WRONG + Utils.UIntToBytes(primflags, ptr); ptr += 4; + eu.Free(); + + ++count; + pos += 12; + + if (pos > (LLUDPServer.MAXPAYLOAD - 13)) + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(data, 0, newbuf.Data, 0, countposition); // start is the same + + data[countposition] = (byte)count; + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false); + + buf = newbuf; + data = buf.Data; + count = 0; + pos = countposition + 1; + break; + } + } + } } - - Utils.UIntToBytes(sop.LocalId, data, pos); pos += 4; - Utils.UIntToBytes((uint)sop.PseudoCRC, data, pos); pos += 4; //WRONG - Utils.UIntToBytes(primflags, data, pos); pos += 4; - - ++count; - if (pos > (LLUDPServer.MAXPAYLOAD - 13)) - { - // 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 = pos; - m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false); - - buf = newbuf; - data = buf.Data; - pos = 18; - - count = 0; - } - eu.Free(); } if (count > 0) { - buf.Data[countposition] = (byte)count; + data[countposition] = (byte)count; buf.DataLength = pos; m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false); } @@ -5456,56 +5469,68 @@ namespace OpenSim.Region.ClientStack.LindenUDP Buffer.BlockCopy(terseUpdateHeader, 0, buf.Data, 0, 7); Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, buf.Data, 7); Utils.UInt16ToBytes(timeDilation, buf.Data, 15); - int pos = 18; + const int COUNTINDEX = 17; + int pos = COUNTINDEX + 1; int lastpos = 0; - int count = 0; EntityUpdate eu; - for (int indx = 0; indx < terseUpdates.Count; ++indx) + int indx = 0; + while (indx < terseUpdates.Count) { - eu = terseUpdates[indx]; - lastpos = pos; - if(eu.Entity is ScenePresence) - CreateAvatartImprovedTerseBlock((ScenePresence)eu.Entity, buf.Data, ref pos); - else - CreatePartImprovedTerseBlock((SceneObjectPart)eu.Entity, buf.Data, ref pos, (eu.Flags & PrimUpdateFlags.Textures) != 0); - if (pos < LLUDPServer.MAXPAYLOAD) + unsafe { - //tau.Add(eu); - ++count; - --blocks; + fixed(byte* bdata = &buf.Data[0]) + { + byte* data = bdata + pos; + while (indx < terseUpdates.Count) + { + eu = terseUpdates[indx++]; + lastpos = pos; + if(eu.Entity is ScenePresence sp) + CreateAvatartImprovedTerseBlock(sp, ref data); + else + CreatePartImprovedTerseBlock((SceneObjectPart)eu.Entity, ref data, (eu.Flags & PrimUpdateFlags.Textures) != 0); + eu.Free(); + pos = (int)(data - bdata); + --blocks; + if (pos < LLUDPServer.MAXPAYLOAD) + { + //tau.Add(eu); + ++count; + } + else if (blocks > 0) + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, COUNTINDEX); // start is the same + // copy what we done in excess + int extralen = pos - lastpos; + if(extralen > 0) + Buffer.BlockCopy(buf.Data, lastpos, newbuf.Data, 18, extralen); + + pos = COUNTINDEX + 1 + extralen; + + buf.Data[COUNTINDEX] = (byte)count; + buf.DataLength = lastpos; + // zero encode is not as spec + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, true); + null, true); + + //tau = new List(30); + //tau.Add(eu); + count = 1; + buf = newbuf; + break; + } + } + } } - else if (blocks > 0) - { - // we need more packets - UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); - Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, 17); // start is the same - // copy what we done in excess - int extralen = pos - lastpos; - if(extralen > 0) - Buffer.BlockCopy(buf.Data, lastpos, newbuf.Data, 18, extralen); - - pos = 18 + extralen; - - buf.Data[17] = (byte)count; - buf.DataLength = lastpos; - // zero encode is not as spec - m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, - //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, true); - null, true); - - //tau = new List(30); - //tau.Add(eu); - count = 1; - --blocks; - buf = newbuf; - } - eu.Free(); //remove if using resend } if (count > 0) { - buf.Data[17] = (byte)count; + buf.Data[COUNTINDEX] = (byte)count; buf.DataLength = pos; m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, true); @@ -6950,8 +6975,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP *data++ = 44; // LocalID - Utils.UIntToBytes(part.LocalId, data); - data += 4; + Utils.UIntToBytes(part.LocalId, data); data += 4; if (part.ParentGroup.AttachmentPoint == 0) *data++ = 0; @@ -6965,8 +6989,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP *data++ = 0; // Position - part.RelativePosition.ToBytes(data); - data += 12; + part.RelativePosition.ToBytes(data); data += 12; // Velocity part.Velocity.ClampedToShortsBytes(128f, data); data += 6; @@ -6984,14 +7007,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (includeTexture && part.Shape.TextureEntry != null) { byte[] te = part.Shape.TextureEntry; - int len = te.Length & 0x7fff; - int totlen = len + 4; - *data++ = (byte)totlen; - *data++ = (byte)(totlen >> 8); - *data++ = (byte)len; // wtf ??? - *data++ = (byte)(len >> 8); - *data++ = 0; - *data++ = 0; + uint len = (uint)te.Length & 0x7fff; + ushort totlen = (ushort)(len + 4); + Utils.UInt16ToBytes(totlen, data); data += 2; + Utils.UIntToBytes(len, data); data += 4; fixed(byte* t = &te[0]) Buffer.MemoryCopy(t, data, 4096, (long)len); data += len; @@ -7081,8 +7100,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //object block size *data++ = 60; // LocalID - Utils.UIntToBytes(presence.LocalId, data); - data += 4; + Utils.UIntToBytes(presence.LocalId, data); data += 4; *data++ = presence.State; @@ -7096,8 +7114,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP data += 16; // Position - presence.OffsetPosition.ToBytes(data); - data += 12; + presence.OffsetPosition.ToBytes(data); data += 12; // Velocity presence.Velocity.ClampedToShortsBytes(128f, data); data += 6; @@ -7122,8 +7139,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP else { a = 1.0f / (float)Math.Sqrt(a); - Utils.FloatToUInt16Bytes(rz * a, 1.0f, data); data += 2; - Utils.FloatToUInt16Bytes(rw * a, 1.0f, data); data += 2; + Utils.UInt16ToBytes(Utils.FloatToUnitUInt16(rz * a), data); data += 2; + Utils.UInt16ToBytes(Utils.FloatToUnitUInt16(rw * a), data); data += 2; } } else @@ -13768,12 +13785,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP //setup header and regioninfo block Buffer.BlockCopy(terseUpdateHeader, 0, buf.Data, 0, 7); - Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, buf.Data, 7); - Utils.UInt16ToBytes(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f), buf.Data, 15); - buf.Data[17] = 1; - int pos = 18; - CreateAvatartImprovedTerseBlock((ScenePresence)p, buf.Data, ref pos); - buf.DataLength = pos; + unsafe + { + fixed(byte* bdata = &buf.Data[0]) + { + Utils.UInt64ToBytes(m_scene.RegionInfo.RegionHandle, bdata + 7); + Utils.UInt16ToBytes(Utils.FloatZeroOneToushort(m_scene.TimeDilation), bdata + 15); + bdata[17] = 1; + byte* data = bdata + 18; + CreateAvatartImprovedTerseBlock((ScenePresence)p, ref data); + buf.DataLength = (int)(data - bdata); + } + } m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, true); } } diff --git a/bin/OpenMetaverse.Rendering.Meshmerizer.dll b/bin/OpenMetaverse.Rendering.Meshmerizer.dll index bc2969d6ee2f93996175e607b12195f0b70ba657..03e6451f39c0383f076f660b37760dbac90a2900 100755 GIT binary patch delta 46 zcmV+}0MY+|paFoO0g#9TTJ8+7i*X|YbbYh_BdP}wX(UO6!gSnApun8dKWS?bv$!ir EB*)Pcwg3PC delta 46 zcmV+}0MY+|paFoO0g#9TQ{fA-i*X|Yv7fX4BdP}wL80>O{sC=3f;)Zx1g{XHv$!ir EB-tkvU;qFB diff --git a/bin/OpenMetaverse.StructuredData.dll b/bin/OpenMetaverse.StructuredData.dll index 52f3240d6c6a4f928cad9fa7f7da318116085cbf..e9e28b8788f4f3e4e7b8fbac7252a5b7bf71437e 100755 GIT binary patch delta 42 zcmV+_0M-A1;0J)<2at#ZSndpgi?xdZeW(ym!v;g1%FRcosP;B%Rf03O7^wm1Mw{ys AEC2ui delta 42 zcmV+_0M-A1;0J)<2at#ZQsE1Mi?xdZeW(ynU0<+R@~ diff --git a/bin/OpenMetaverse.dll b/bin/OpenMetaverse.dll index 7e4e7a0017eaf691fc3e5a6ddafe3c68be1f4747..cc233d5729f5f5f4938bc945cf2284c0407161d7 100755 GIT binary patch delta 169 zcmWN=yAHun00v;E?v%P;>b}^KNMFF*mBmw7MVt6l@-JRN;tfQ)7)>I?C^47~L}D=r zCtp76HWik&hVtmCAlnD+~KLZpCs delta 169 zcmWN=yAHu%00z)j-KuEasrws{82SJPTL*i+hC!kdUr4^iATf%`EFygYlZeJ_AqI;@ zV&~7vaqm;v6&G`*|Ij7`WiS9LU=R#}VK4$lK^2UF8W;x?U=q|p15ANwFau`69GC|S zU=b`GXkIUY-FoKurdSp$V%2l}+G%XOZ%;qG+;%ssVPeo5y=InO_bj_{KB^t5C0Rmy N|B=6%CpVfu{SVi-M1ueT diff --git a/bin/OpenMetaverseTypes.dll b/bin/OpenMetaverseTypes.dll index b655e654e4c47869a35dba54c2b7166302351c61..96c88b0d06183b8bc9ccf36f2b81cc67646208b1 100755 GIT binary patch delta 14326 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%0A( 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 e1%jI&P^|I6*qO>NHl0-1>;2d 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