From 5035de053a533bb0407fb8ad11c44351026f6cf8 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 25 Mar 2019 17:51:38 +0000 Subject: [PATCH] we should be able to zeroencode compressedupdates --- .../ClientStack/Linden/UDP/LLClientView.cs | 456 ++++++++++++++++-- 1 file changed, 425 insertions(+), 31 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 601de61de2..187b6fa7c4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4857,6 +4857,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } useCompressUpdate = false; + bool istree = false; if (update.Entity is SceneObjectPart) { @@ -4973,8 +4974,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP maxUpdatesBytes -= 20 * part.Animations.Count + 24; } } + if(viewerCache) useCompressUpdate = grp.IsViewerCachable; + + istree = (part.Shape.PCode == (byte)PCode.Grass || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Tree); } else if (update.Entity is ScenePresence) { @@ -5049,7 +5053,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (useCompressUpdate) { - maxUpdatesBytes -= 150; // crude estimation + if (istree) + maxUpdatesBytes -= 64; + else + maxUpdatesBytes -= 100; // crude estimation if (compressedUpdates == null) { @@ -5060,7 +5067,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - maxUpdatesBytes -= 150; // crude estimation + if (istree) + maxUpdatesBytes -= 70; + else + maxUpdatesBytes -= 150; // crude estimation if (objectUpdates == null) { @@ -5164,6 +5174,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + /* no zero encode compressed updates if(compressedUpdates != null) { List tau = new List(30); @@ -5211,7 +5222,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP pos = 18; // im lazy now, just do last again - CreateCompressedUpdateBlock((SceneObjectPart)eu.Entity, mysp, data, ref pos); + CreateCompressedUpdateBlock(sop, mysp, data, ref pos); tau = new List(30); tau.Add(eu); count = 1; @@ -5226,6 +5237,88 @@ namespace OpenSim.Region.ClientStack.LindenUDP delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); } } + */ + + 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); + data[0] |= Helpers.MSG_ZEROCODED; + + LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); + zc.Position = 7; + + zc.AddUInt64(m_scene.RegionInfo.RegionHandle); + zc.AddUInt16(timeDilation); + + zc.AddByte(1); // tmp block count + + int countposition = zc.Position - 1; + + int lastpos = 0; + int lastzc = 0; + + int count = 0; + foreach (EntityUpdate eu in compressedUpdates) + { + SceneObjectPart sop = (SceneObjectPart)eu.Entity; + if (sop.ParentGroup == null || sop.ParentGroup.IsDeleted) + continue; + lastpos = zc.Position; + lastzc = zc.ZeroCount; + + CreateCompressedUpdateBlockZC(sop, mysp, zc); + if (zc.Position < 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; + // get pending zeros at cut point + if (lastzc > 0) + { + buf.Data[lastpos++] = 0; + buf.Data[lastpos++] = (byte)lastzc; + } + buf.DataLength = lastpos; + + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + + buf = newbuf; + zc.Data = buf.Data; + + data[0] |= Helpers.MSG_ZEROCODED; + + zc.ZeroCount = 0; + zc.Position = countposition + 1; + + // im lazy now, just do last again + CreateCompressedUpdateBlockZC(sop, mysp, zc); + tau = new List(30); + tau.Add(eu); + count = 1; + } + } + + if (count > 0) + { + buf.Data[countposition] = (byte)count; + buf.DataLength = zc.Finish(); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + } + } if (objectUpdateProbes != null) { @@ -7174,9 +7267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP HasParticlesNew = 0x400 } - ///**** temp hack - private static Random rnd = new Random(); - + /* protected void CreateCompressedUpdateBlock(SceneObjectPart part, ScenePresence sp, byte[] dest, ref int pos) { // prepare data @@ -7197,13 +7288,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - // first is primFlags - Utils.UIntToBytesSafepos((uint)primflags, dest, pos); pos += 4; - - // datablock len to fill later - int lenpos = pos; - pos += 2; - byte state = part.Shape.State; PCode pcode = (PCode)part.Shape.PCode; @@ -7278,12 +7362,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP pathScaleY = 150; } + // first is primFlags + Utils.UIntToBytesSafepos((uint)primflags, dest, pos); pos += 4; + + // datablock len to fill later + int lenpos = pos; + pos += 2; + + // data block part.UUID.ToBytes(dest, pos); pos += 16; Utils.UIntToBytesSafepos(part.LocalId, dest, pos); pos += 4; dest[pos++] = (byte)pcode; dest[pos++] = state; - ///**** temp hack Utils.UIntToBytesSafepos((uint)part.ParentGroup.PseudoCRC, dest, pos); pos += 4; dest[pos++] = part.Material; dest[pos++] = part.ClickAction; @@ -7393,23 +7484,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (hastexanim) { byte[] ta = part.TextureAnimation; - if (ta == null) - { - dest[pos++] = 0; - dest[pos++] = 0; - dest[pos++] = 0; - dest[pos++] = 0; - } - else - { - int len = ta.Length & 0x7fff; - dest[pos++] = (byte)len; - dest[pos++] = (byte)(len >> 8); - dest[pos++] = 0; - dest[pos++] = 0; - Buffer.BlockCopy(ta, 0, dest, pos, len); - pos += len; - } + int len = ta.Length & 0x7fff; + dest[pos++] = (byte)len; + dest[pos++] = (byte)(len >> 8); + dest[pos++] = 0; + dest[pos++] = 0; + Buffer.BlockCopy(ta, 0, dest, pos, len); + pos += len; } if (haspsnew) @@ -7422,6 +7503,319 @@ namespace OpenSim.Region.ClientStack.LindenUDP dest[lenpos++] = (byte)totlen; dest[lenpos++] = (byte)(totlen >> 8); } + */ + + protected void CreateCompressedUpdateBlockZC(SceneObjectPart part, ScenePresence sp, LLUDPZeroEncoder zc) + { + // prepare data + CompressedFlags cflags = CompressedFlags.None; + + // prim/update flags + + PrimFlags primflags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp); + // Don't send the CreateSelected flag to everyone + primflags &= ~PrimFlags.CreateSelected; + if (sp.UUID == part.OwnerID) + { + if (part.CreateSelected) + { + // Only send this flag once, then unset it + primflags |= PrimFlags.CreateSelected; + part.CreateSelected = false; + } + } + + byte state = part.Shape.State; + PCode pcode = (PCode)part.Shape.PCode; + + // trees and grass are a lot more compact + if (pcode == PCode.Grass || pcode == PCode.Tree || pcode == PCode.NewTree) + { + // first is primFlags + zc.AddUInt((uint)primflags); + + // datablock len + zc.AddByte(113); + zc.AddZeros(1); + + // data block + zc.AddUUID(part.UUID); + zc.AddUInt(part.LocalId); + zc.AddByte((byte)pcode); + zc.AddByte(state); + + zc.AddUInt((uint)part.ParentGroup.PseudoCRC); + + zc.AddZeros(2); // material and click action + + zc.AddVector3(part.Shape.Scale); + zc.AddVector3(part.RelativePosition); + if (pcode == PCode.Grass) + zc.AddZeros(12); + else + { + Quaternion rotation = part.RotationOffset; + rotation.Normalize(); + zc.AddNormQuat(rotation); + } + + zc.AddUInt((uint)CompressedFlags.Tree); // cflags + + zc.AddZeros(16); // owner id + + zc.AddByte(state); // tree parameter + + zc.AddZeros(28); //extraparameters 1, pbs 23, texture 4 + + return; + } + + //NameValue and state + byte[] nv = null; + if (part.ParentGroup.IsAttachment) + { + if (part.IsRoot) + nv = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID); + + int st = (int)part.ParentGroup.AttachmentPoint; + state = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; + } + + bool hastext = false; + bool hassound = false; + bool hasps = false; + bool hastexanim = false; + bool hasangvel = false; + bool hasmediaurl = false; + bool haspsnew = false; + + int BlockLengh = 111; + + byte[] extraParamBytes = part.Shape.ExtraParams; + if (extraParamBytes == null || extraParamBytes.Length < 2) + { + ++BlockLengh; + extraParamBytes = null; + } + else + BlockLengh += extraParamBytes.Length; + + byte[] hoverText = null; + byte[] hoverTextColor = null; + if (part.Text != null && part.Text.Length > 0) + { + cflags |= CompressedFlags.HasText; + hoverText = Util.StringToBytes256(part.Text); + BlockLengh += hoverText.Length; + hoverTextColor = part.GetTextColor().GetBytes(false); + BlockLengh += hoverTextColor.Length; + hastext = true; + } + + if (part.ParticleSystem != null && part.ParticleSystem.Length > 1) + { + BlockLengh += part.ParticleSystem.Length; + if (part.ParticleSystem.Length > 86) + { + hasps = false; + cflags |= CompressedFlags.HasParticlesNew; + haspsnew = true; + } + else + { + cflags |= CompressedFlags.HasParticlesLegacy; + hasps = true; + } + } + + if (part.Sound != UUID.Zero || part.SoundFlags != 0) + { + BlockLengh += 25; + cflags |= CompressedFlags.HasSound; + hassound = true; + } + + if (part.ParentID != 0) + { + BlockLengh += 4; + cflags |= CompressedFlags.HasParent; + } + + if (part.TextureAnimation != null && part.TextureAnimation.Length > 0) + { + BlockLengh += part.TextureAnimation.Length + 4; + cflags |= CompressedFlags.TextureAnimation; + hastexanim = true; + } + + if (part.AngularVelocity.LengthSquared() > 1e-8f) + { + BlockLengh += 12; + cflags |= CompressedFlags.HasAngularVelocity; + hasangvel = true; + } + + byte[] mediaURLBytes = null; + if (part.MediaUrl != null && part.MediaUrl.Length > 1) + { + mediaURLBytes = Util.StringToBytes256(part.MediaUrl); // must be null term + BlockLengh += mediaURLBytes.Length; + cflags |= CompressedFlags.MediaURL; + hasmediaurl = true; + } + + if (nv != null) + { + BlockLengh += nv.Length; + cflags |= CompressedFlags.HasNameValues; + } + + byte[] textureEntry = part.Shape.TextureEntry; + if(textureEntry != null) + BlockLengh += textureEntry.Length; + + // filter out mesh faces hack + ushort profileBegin = part.Shape.ProfileBegin; + ushort profileHollow = part.Shape.ProfileHollow; + byte profileCurve = part.Shape.ProfileCurve; + byte pathScaleY = part.Shape.PathScaleY; + + if (part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack + { + profileCurve = (byte)(part.Shape.ProfileCurve & 0x0f); + // fix old values that confused viewers + if (profileBegin == 1) + profileBegin = 9375; + if (profileHollow == 1) + profileHollow = 27500; + // fix torus hole size Y that also confuse some viewers + if (profileCurve == (byte)ProfileShape.Circle && pathScaleY < 150) + pathScaleY = 150; + } + + + // first is primFlags + zc.AddUInt((uint)primflags); + + // datablock len + zc.AddByte((byte)BlockLengh); + zc.AddByte((byte)(BlockLengh >> 8)); + + // data block + zc.AddUUID(part.UUID); + zc.AddUInt(part.LocalId); + zc.AddByte((byte)pcode); + zc.AddByte(state); + + zc.AddUInt((uint)part.ParentGroup.PseudoCRC); + + zc.AddByte(part.Material); + zc.AddByte(part.ClickAction); + zc.AddVector3(part.Shape.Scale); + zc.AddVector3(part.RelativePosition); + if (pcode == PCode.Grass) + zc.AddZeros(12); + else + { + Quaternion rotation = part.RotationOffset; + rotation.Normalize(); + zc.AddNormQuat(rotation); + } + + zc.AddUInt((uint)cflags); + + if (hasps || haspsnew || hassound) + zc.AddUUID(part.OwnerID); + else + zc.AddZeros(16); + + if (hasangvel) + { + zc.AddVector3(part.AngularVelocity); + } + if (part.ParentID != 0) + { + zc.AddUInt(part.ParentID); + } + if (hastext) + { + zc.AddBytes(hoverText, hoverText.Length); + zc.AddBytes(hoverTextColor, hoverTextColor.Length); + } + if (hasmediaurl) + { + zc.AddBytes(mediaURLBytes, mediaURLBytes.Length); + } + if (hasps) + { + byte[] ps = part.ParticleSystem; + zc.AddBytes(ps, ps.Length); + } + if (extraParamBytes == null) + zc.AddZeros(1); + else + { + zc.AddBytes(extraParamBytes, extraParamBytes.Length); + } + if (hassound) + { + zc.AddUUID(part.Sound); + zc.AddFloat((float)part.SoundGain); + zc.AddByte(part.SoundFlags); + zc.AddFloat((float)part.SoundRadius); + } + if (nv != null) + { + zc.AddBytes(nv, nv.Length); + } + + zc.AddByte(part.Shape.PathCurve); + zc.AddUInt16(part.Shape.PathBegin); + zc.AddUInt16(part.Shape.PathEnd); + zc.AddByte(part.Shape.PathScaleX); + zc.AddByte(pathScaleY); + zc.AddByte(part.Shape.PathShearX); + zc.AddByte(part.Shape.PathShearY); + zc.AddByte((byte)part.Shape.PathTwist); + zc.AddByte((byte)part.Shape.PathTwistBegin); + zc.AddByte((byte)part.Shape.PathRadiusOffset); + zc.AddByte((byte)part.Shape.PathTaperX); + zc.AddByte((byte)part.Shape.PathTaperY); + zc.AddByte(part.Shape.PathRevolutions); + zc.AddByte((byte)part.Shape.PathSkew); + zc.AddByte(profileCurve); + zc.AddUInt16(profileBegin); + zc.AddUInt16(part.Shape.ProfileEnd); + zc.AddUInt16(profileHollow); + + if (textureEntry == null) + { + zc.AddZeros(4); + } + else + { + int len = textureEntry.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddZeros(2); + zc.AddBytes(textureEntry, len); + } + if (hastexanim) + { + byte[] ta = part.TextureAnimation; + int len = ta.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddZeros(2); + zc.AddBytes(ta, len); + } + + if (haspsnew) + { + byte[] ps = part.ParticleSystem; + zc.AddBytes(ps, ps.Length); + } + } public void SendNameReply(UUID profileId, string firstname, string lastname) {