diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 456 |
1 files changed, 425 insertions, 31 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 601de61..187b6fa 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 | |||
4857 | } | 4857 | } |
4858 | 4858 | ||
4859 | useCompressUpdate = false; | 4859 | useCompressUpdate = false; |
4860 | bool istree = false; | ||
4860 | 4861 | ||
4861 | if (update.Entity is SceneObjectPart) | 4862 | if (update.Entity is SceneObjectPart) |
4862 | { | 4863 | { |
@@ -4973,8 +4974,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4973 | maxUpdatesBytes -= 20 * part.Animations.Count + 24; | 4974 | maxUpdatesBytes -= 20 * part.Animations.Count + 24; |
4974 | } | 4975 | } |
4975 | } | 4976 | } |
4977 | |||
4976 | if(viewerCache) | 4978 | if(viewerCache) |
4977 | useCompressUpdate = grp.IsViewerCachable; | 4979 | useCompressUpdate = grp.IsViewerCachable; |
4980 | |||
4981 | istree = (part.Shape.PCode == (byte)PCode.Grass || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Tree); | ||
4978 | } | 4982 | } |
4979 | else if (update.Entity is ScenePresence) | 4983 | else if (update.Entity is ScenePresence) |
4980 | { | 4984 | { |
@@ -5049,7 +5053,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5049 | { | 5053 | { |
5050 | if (useCompressUpdate) | 5054 | if (useCompressUpdate) |
5051 | { | 5055 | { |
5052 | maxUpdatesBytes -= 150; // crude estimation | 5056 | if (istree) |
5057 | maxUpdatesBytes -= 64; | ||
5058 | else | ||
5059 | maxUpdatesBytes -= 100; // crude estimation | ||
5053 | 5060 | ||
5054 | if (compressedUpdates == null) | 5061 | if (compressedUpdates == null) |
5055 | { | 5062 | { |
@@ -5060,7 +5067,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5060 | } | 5067 | } |
5061 | else | 5068 | else |
5062 | { | 5069 | { |
5063 | maxUpdatesBytes -= 150; // crude estimation | 5070 | if (istree) |
5071 | maxUpdatesBytes -= 70; | ||
5072 | else | ||
5073 | maxUpdatesBytes -= 150; // crude estimation | ||
5064 | 5074 | ||
5065 | if (objectUpdates == null) | 5075 | if (objectUpdates == null) |
5066 | { | 5076 | { |
@@ -5164,6 +5174,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5164 | } | 5174 | } |
5165 | } | 5175 | } |
5166 | 5176 | ||
5177 | /* no zero encode compressed updates | ||
5167 | if(compressedUpdates != null) | 5178 | if(compressedUpdates != null) |
5168 | { | 5179 | { |
5169 | List<EntityUpdate> tau = new List<EntityUpdate>(30); | 5180 | List<EntityUpdate> tau = new List<EntityUpdate>(30); |
@@ -5211,7 +5222,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5211 | 5222 | ||
5212 | pos = 18; | 5223 | pos = 18; |
5213 | // im lazy now, just do last again | 5224 | // im lazy now, just do last again |
5214 | CreateCompressedUpdateBlock((SceneObjectPart)eu.Entity, mysp, data, ref pos); | 5225 | CreateCompressedUpdateBlock(sop, mysp, data, ref pos); |
5215 | tau = new List<EntityUpdate>(30); | 5226 | tau = new List<EntityUpdate>(30); |
5216 | tau.Add(eu); | 5227 | tau.Add(eu); |
5217 | count = 1; | 5228 | count = 1; |
@@ -5226,6 +5237,88 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5226 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); | 5237 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); |
5227 | } | 5238 | } |
5228 | } | 5239 | } |
5240 | */ | ||
5241 | |||
5242 | if (compressedUpdates != null) | ||
5243 | { | ||
5244 | List<EntityUpdate> tau = new List<EntityUpdate>(30); | ||
5245 | |||
5246 | UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); | ||
5247 | byte[] data = buf.Data; | ||
5248 | |||
5249 | Buffer.BlockCopy(CompressedObjectHeader, 0, data, 0, 7); | ||
5250 | data[0] |= Helpers.MSG_ZEROCODED; | ||
5251 | |||
5252 | LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); | ||
5253 | zc.Position = 7; | ||
5254 | |||
5255 | zc.AddUInt64(m_scene.RegionInfo.RegionHandle); | ||
5256 | zc.AddUInt16(timeDilation); | ||
5257 | |||
5258 | zc.AddByte(1); // tmp block count | ||
5259 | |||
5260 | int countposition = zc.Position - 1; | ||
5261 | |||
5262 | int lastpos = 0; | ||
5263 | int lastzc = 0; | ||
5264 | |||
5265 | int count = 0; | ||
5266 | foreach (EntityUpdate eu in compressedUpdates) | ||
5267 | { | ||
5268 | SceneObjectPart sop = (SceneObjectPart)eu.Entity; | ||
5269 | if (sop.ParentGroup == null || sop.ParentGroup.IsDeleted) | ||
5270 | continue; | ||
5271 | lastpos = zc.Position; | ||
5272 | lastzc = zc.ZeroCount; | ||
5273 | |||
5274 | CreateCompressedUpdateBlockZC(sop, mysp, zc); | ||
5275 | if (zc.Position < LLUDPServer.MAXPAYLOAD) | ||
5276 | { | ||
5277 | tau.Add(eu); | ||
5278 | ++count; | ||
5279 | } | ||
5280 | else | ||
5281 | { | ||
5282 | // we need more packets | ||
5283 | UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); | ||
5284 | Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same | ||
5285 | |||
5286 | buf.Data[countposition] = (byte)count; | ||
5287 | // get pending zeros at cut point | ||
5288 | if (lastzc > 0) | ||
5289 | { | ||
5290 | buf.Data[lastpos++] = 0; | ||
5291 | buf.Data[lastpos++] = (byte)lastzc; | ||
5292 | } | ||
5293 | buf.DataLength = lastpos; | ||
5294 | |||
5295 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, | ||
5296 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); | ||
5297 | |||
5298 | buf = newbuf; | ||
5299 | zc.Data = buf.Data; | ||
5300 | |||
5301 | data[0] |= Helpers.MSG_ZEROCODED; | ||
5302 | |||
5303 | zc.ZeroCount = 0; | ||
5304 | zc.Position = countposition + 1; | ||
5305 | |||
5306 | // im lazy now, just do last again | ||
5307 | CreateCompressedUpdateBlockZC(sop, mysp, zc); | ||
5308 | tau = new List<EntityUpdate>(30); | ||
5309 | tau.Add(eu); | ||
5310 | count = 1; | ||
5311 | } | ||
5312 | } | ||
5313 | |||
5314 | if (count > 0) | ||
5315 | { | ||
5316 | buf.Data[countposition] = (byte)count; | ||
5317 | buf.DataLength = zc.Finish(); | ||
5318 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, | ||
5319 | delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); | ||
5320 | } | ||
5321 | } | ||
5229 | 5322 | ||
5230 | if (objectUpdateProbes != null) | 5323 | if (objectUpdateProbes != null) |
5231 | { | 5324 | { |
@@ -7174,9 +7267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7174 | HasParticlesNew = 0x400 | 7267 | HasParticlesNew = 0x400 |
7175 | } | 7268 | } |
7176 | 7269 | ||
7177 | ///**** temp hack | 7270 | /* |
7178 | private static Random rnd = new Random(); | ||
7179 | |||
7180 | protected void CreateCompressedUpdateBlock(SceneObjectPart part, ScenePresence sp, byte[] dest, ref int pos) | 7271 | protected void CreateCompressedUpdateBlock(SceneObjectPart part, ScenePresence sp, byte[] dest, ref int pos) |
7181 | { | 7272 | { |
7182 | // prepare data | 7273 | // prepare data |
@@ -7197,13 +7288,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7197 | } | 7288 | } |
7198 | } | 7289 | } |
7199 | 7290 | ||
7200 | // first is primFlags | ||
7201 | Utils.UIntToBytesSafepos((uint)primflags, dest, pos); pos += 4; | ||
7202 | |||
7203 | // datablock len to fill later | ||
7204 | int lenpos = pos; | ||
7205 | pos += 2; | ||
7206 | |||
7207 | byte state = part.Shape.State; | 7291 | byte state = part.Shape.State; |
7208 | PCode pcode = (PCode)part.Shape.PCode; | 7292 | PCode pcode = (PCode)part.Shape.PCode; |
7209 | 7293 | ||
@@ -7278,12 +7362,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7278 | pathScaleY = 150; | 7362 | pathScaleY = 150; |
7279 | } | 7363 | } |
7280 | 7364 | ||
7365 | // first is primFlags | ||
7366 | Utils.UIntToBytesSafepos((uint)primflags, dest, pos); pos += 4; | ||
7367 | |||
7368 | // datablock len to fill later | ||
7369 | int lenpos = pos; | ||
7370 | pos += 2; | ||
7371 | |||
7372 | // data block | ||
7281 | part.UUID.ToBytes(dest, pos); pos += 16; | 7373 | part.UUID.ToBytes(dest, pos); pos += 16; |
7282 | Utils.UIntToBytesSafepos(part.LocalId, dest, pos); pos += 4; | 7374 | Utils.UIntToBytesSafepos(part.LocalId, dest, pos); pos += 4; |
7283 | dest[pos++] = (byte)pcode; | 7375 | dest[pos++] = (byte)pcode; |
7284 | dest[pos++] = state; | 7376 | dest[pos++] = state; |
7285 | 7377 | ||
7286 | ///**** temp hack | ||
7287 | Utils.UIntToBytesSafepos((uint)part.ParentGroup.PseudoCRC, dest, pos); pos += 4; | 7378 | Utils.UIntToBytesSafepos((uint)part.ParentGroup.PseudoCRC, dest, pos); pos += 4; |
7288 | dest[pos++] = part.Material; | 7379 | dest[pos++] = part.Material; |
7289 | dest[pos++] = part.ClickAction; | 7380 | dest[pos++] = part.ClickAction; |
@@ -7393,23 +7484,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7393 | if (hastexanim) | 7484 | if (hastexanim) |
7394 | { | 7485 | { |
7395 | byte[] ta = part.TextureAnimation; | 7486 | byte[] ta = part.TextureAnimation; |
7396 | if (ta == null) | 7487 | int len = ta.Length & 0x7fff; |
7397 | { | 7488 | dest[pos++] = (byte)len; |
7398 | dest[pos++] = 0; | 7489 | dest[pos++] = (byte)(len >> 8); |
7399 | dest[pos++] = 0; | 7490 | dest[pos++] = 0; |
7400 | dest[pos++] = 0; | 7491 | dest[pos++] = 0; |
7401 | dest[pos++] = 0; | 7492 | Buffer.BlockCopy(ta, 0, dest, pos, len); |
7402 | } | 7493 | pos += len; |
7403 | else | ||
7404 | { | ||
7405 | int len = ta.Length & 0x7fff; | ||
7406 | dest[pos++] = (byte)len; | ||
7407 | dest[pos++] = (byte)(len >> 8); | ||
7408 | dest[pos++] = 0; | ||
7409 | dest[pos++] = 0; | ||
7410 | Buffer.BlockCopy(ta, 0, dest, pos, len); | ||
7411 | pos += len; | ||
7412 | } | ||
7413 | } | 7494 | } |
7414 | 7495 | ||
7415 | if (haspsnew) | 7496 | if (haspsnew) |
@@ -7422,6 +7503,319 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7422 | dest[lenpos++] = (byte)totlen; | 7503 | dest[lenpos++] = (byte)totlen; |
7423 | dest[lenpos++] = (byte)(totlen >> 8); | 7504 | dest[lenpos++] = (byte)(totlen >> 8); |
7424 | } | 7505 | } |
7506 | */ | ||
7507 | |||
7508 | protected void CreateCompressedUpdateBlockZC(SceneObjectPart part, ScenePresence sp, LLUDPZeroEncoder zc) | ||
7509 | { | ||
7510 | // prepare data | ||
7511 | CompressedFlags cflags = CompressedFlags.None; | ||
7512 | |||
7513 | // prim/update flags | ||
7514 | |||
7515 | PrimFlags primflags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp); | ||
7516 | // Don't send the CreateSelected flag to everyone | ||
7517 | primflags &= ~PrimFlags.CreateSelected; | ||
7518 | if (sp.UUID == part.OwnerID) | ||
7519 | { | ||
7520 | if (part.CreateSelected) | ||
7521 | { | ||
7522 | // Only send this flag once, then unset it | ||
7523 | primflags |= PrimFlags.CreateSelected; | ||
7524 | part.CreateSelected = false; | ||
7525 | } | ||
7526 | } | ||
7527 | |||
7528 | byte state = part.Shape.State; | ||
7529 | PCode pcode = (PCode)part.Shape.PCode; | ||
7530 | |||
7531 | // trees and grass are a lot more compact | ||
7532 | if (pcode == PCode.Grass || pcode == PCode.Tree || pcode == PCode.NewTree) | ||
7533 | { | ||
7534 | // first is primFlags | ||
7535 | zc.AddUInt((uint)primflags); | ||
7536 | |||
7537 | // datablock len | ||
7538 | zc.AddByte(113); | ||
7539 | zc.AddZeros(1); | ||
7540 | |||
7541 | // data block | ||
7542 | zc.AddUUID(part.UUID); | ||
7543 | zc.AddUInt(part.LocalId); | ||
7544 | zc.AddByte((byte)pcode); | ||
7545 | zc.AddByte(state); | ||
7546 | |||
7547 | zc.AddUInt((uint)part.ParentGroup.PseudoCRC); | ||
7548 | |||
7549 | zc.AddZeros(2); // material and click action | ||
7550 | |||
7551 | zc.AddVector3(part.Shape.Scale); | ||
7552 | zc.AddVector3(part.RelativePosition); | ||
7553 | if (pcode == PCode.Grass) | ||
7554 | zc.AddZeros(12); | ||
7555 | else | ||
7556 | { | ||
7557 | Quaternion rotation = part.RotationOffset; | ||
7558 | rotation.Normalize(); | ||
7559 | zc.AddNormQuat(rotation); | ||
7560 | } | ||
7561 | |||
7562 | zc.AddUInt((uint)CompressedFlags.Tree); // cflags | ||
7563 | |||
7564 | zc.AddZeros(16); // owner id | ||
7565 | |||
7566 | zc.AddByte(state); // tree parameter | ||
7567 | |||
7568 | zc.AddZeros(28); //extraparameters 1, pbs 23, texture 4 | ||
7569 | |||
7570 | return; | ||
7571 | } | ||
7572 | |||
7573 | //NameValue and state | ||
7574 | byte[] nv = null; | ||
7575 | if (part.ParentGroup.IsAttachment) | ||
7576 | { | ||
7577 | if (part.IsRoot) | ||
7578 | nv = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID); | ||
7579 | |||
7580 | int st = (int)part.ParentGroup.AttachmentPoint; | ||
7581 | state = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; | ||
7582 | } | ||
7583 | |||
7584 | bool hastext = false; | ||
7585 | bool hassound = false; | ||
7586 | bool hasps = false; | ||
7587 | bool hastexanim = false; | ||
7588 | bool hasangvel = false; | ||
7589 | bool hasmediaurl = false; | ||
7590 | bool haspsnew = false; | ||
7591 | |||
7592 | int BlockLengh = 111; | ||
7593 | |||
7594 | byte[] extraParamBytes = part.Shape.ExtraParams; | ||
7595 | if (extraParamBytes == null || extraParamBytes.Length < 2) | ||
7596 | { | ||
7597 | ++BlockLengh; | ||
7598 | extraParamBytes = null; | ||
7599 | } | ||
7600 | else | ||
7601 | BlockLengh += extraParamBytes.Length; | ||
7602 | |||
7603 | byte[] hoverText = null; | ||
7604 | byte[] hoverTextColor = null; | ||
7605 | if (part.Text != null && part.Text.Length > 0) | ||
7606 | { | ||
7607 | cflags |= CompressedFlags.HasText; | ||
7608 | hoverText = Util.StringToBytes256(part.Text); | ||
7609 | BlockLengh += hoverText.Length; | ||
7610 | hoverTextColor = part.GetTextColor().GetBytes(false); | ||
7611 | BlockLengh += hoverTextColor.Length; | ||
7612 | hastext = true; | ||
7613 | } | ||
7614 | |||
7615 | if (part.ParticleSystem != null && part.ParticleSystem.Length > 1) | ||
7616 | { | ||
7617 | BlockLengh += part.ParticleSystem.Length; | ||
7618 | if (part.ParticleSystem.Length > 86) | ||
7619 | { | ||
7620 | hasps = false; | ||
7621 | cflags |= CompressedFlags.HasParticlesNew; | ||
7622 | haspsnew = true; | ||
7623 | } | ||
7624 | else | ||
7625 | { | ||
7626 | cflags |= CompressedFlags.HasParticlesLegacy; | ||
7627 | hasps = true; | ||
7628 | } | ||
7629 | } | ||
7630 | |||
7631 | if (part.Sound != UUID.Zero || part.SoundFlags != 0) | ||
7632 | { | ||
7633 | BlockLengh += 25; | ||
7634 | cflags |= CompressedFlags.HasSound; | ||
7635 | hassound = true; | ||
7636 | } | ||
7637 | |||
7638 | if (part.ParentID != 0) | ||
7639 | { | ||
7640 | BlockLengh += 4; | ||
7641 | cflags |= CompressedFlags.HasParent; | ||
7642 | } | ||
7643 | |||
7644 | if (part.TextureAnimation != null && part.TextureAnimation.Length > 0) | ||
7645 | { | ||
7646 | BlockLengh += part.TextureAnimation.Length + 4; | ||
7647 | cflags |= CompressedFlags.TextureAnimation; | ||
7648 | hastexanim = true; | ||
7649 | } | ||
7650 | |||
7651 | if (part.AngularVelocity.LengthSquared() > 1e-8f) | ||
7652 | { | ||
7653 | BlockLengh += 12; | ||
7654 | cflags |= CompressedFlags.HasAngularVelocity; | ||
7655 | hasangvel = true; | ||
7656 | } | ||
7657 | |||
7658 | byte[] mediaURLBytes = null; | ||
7659 | if (part.MediaUrl != null && part.MediaUrl.Length > 1) | ||
7660 | { | ||
7661 | mediaURLBytes = Util.StringToBytes256(part.MediaUrl); // must be null term | ||
7662 | BlockLengh += mediaURLBytes.Length; | ||
7663 | cflags |= CompressedFlags.MediaURL; | ||
7664 | hasmediaurl = true; | ||
7665 | } | ||
7666 | |||
7667 | if (nv != null) | ||
7668 | { | ||
7669 | BlockLengh += nv.Length; | ||
7670 | cflags |= CompressedFlags.HasNameValues; | ||
7671 | } | ||
7672 | |||
7673 | byte[] textureEntry = part.Shape.TextureEntry; | ||
7674 | if(textureEntry != null) | ||
7675 | BlockLengh += textureEntry.Length; | ||
7676 | |||
7677 | // filter out mesh faces hack | ||
7678 | ushort profileBegin = part.Shape.ProfileBegin; | ||
7679 | ushort profileHollow = part.Shape.ProfileHollow; | ||
7680 | byte profileCurve = part.Shape.ProfileCurve; | ||
7681 | byte pathScaleY = part.Shape.PathScaleY; | ||
7682 | |||
7683 | if (part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack | ||
7684 | { | ||
7685 | profileCurve = (byte)(part.Shape.ProfileCurve & 0x0f); | ||
7686 | // fix old values that confused viewers | ||
7687 | if (profileBegin == 1) | ||
7688 | profileBegin = 9375; | ||
7689 | if (profileHollow == 1) | ||
7690 | profileHollow = 27500; | ||
7691 | // fix torus hole size Y that also confuse some viewers | ||
7692 | if (profileCurve == (byte)ProfileShape.Circle && pathScaleY < 150) | ||
7693 | pathScaleY = 150; | ||
7694 | } | ||
7695 | |||
7696 | |||
7697 | // first is primFlags | ||
7698 | zc.AddUInt((uint)primflags); | ||
7699 | |||
7700 | // datablock len | ||
7701 | zc.AddByte((byte)BlockLengh); | ||
7702 | zc.AddByte((byte)(BlockLengh >> 8)); | ||
7703 | |||
7704 | // data block | ||
7705 | zc.AddUUID(part.UUID); | ||
7706 | zc.AddUInt(part.LocalId); | ||
7707 | zc.AddByte((byte)pcode); | ||
7708 | zc.AddByte(state); | ||
7709 | |||
7710 | zc.AddUInt((uint)part.ParentGroup.PseudoCRC); | ||
7711 | |||
7712 | zc.AddByte(part.Material); | ||
7713 | zc.AddByte(part.ClickAction); | ||
7714 | zc.AddVector3(part.Shape.Scale); | ||
7715 | zc.AddVector3(part.RelativePosition); | ||
7716 | if (pcode == PCode.Grass) | ||
7717 | zc.AddZeros(12); | ||
7718 | else | ||
7719 | { | ||
7720 | Quaternion rotation = part.RotationOffset; | ||
7721 | rotation.Normalize(); | ||
7722 | zc.AddNormQuat(rotation); | ||
7723 | } | ||
7724 | |||
7725 | zc.AddUInt((uint)cflags); | ||
7726 | |||
7727 | if (hasps || haspsnew || hassound) | ||
7728 | zc.AddUUID(part.OwnerID); | ||
7729 | else | ||
7730 | zc.AddZeros(16); | ||
7731 | |||
7732 | if (hasangvel) | ||
7733 | { | ||
7734 | zc.AddVector3(part.AngularVelocity); | ||
7735 | } | ||
7736 | if (part.ParentID != 0) | ||
7737 | { | ||
7738 | zc.AddUInt(part.ParentID); | ||
7739 | } | ||
7740 | if (hastext) | ||
7741 | { | ||
7742 | zc.AddBytes(hoverText, hoverText.Length); | ||
7743 | zc.AddBytes(hoverTextColor, hoverTextColor.Length); | ||
7744 | } | ||
7745 | if (hasmediaurl) | ||
7746 | { | ||
7747 | zc.AddBytes(mediaURLBytes, mediaURLBytes.Length); | ||
7748 | } | ||
7749 | if (hasps) | ||
7750 | { | ||
7751 | byte[] ps = part.ParticleSystem; | ||
7752 | zc.AddBytes(ps, ps.Length); | ||
7753 | } | ||
7754 | if (extraParamBytes == null) | ||
7755 | zc.AddZeros(1); | ||
7756 | else | ||
7757 | { | ||
7758 | zc.AddBytes(extraParamBytes, extraParamBytes.Length); | ||
7759 | } | ||
7760 | if (hassound) | ||
7761 | { | ||
7762 | zc.AddUUID(part.Sound); | ||
7763 | zc.AddFloat((float)part.SoundGain); | ||
7764 | zc.AddByte(part.SoundFlags); | ||
7765 | zc.AddFloat((float)part.SoundRadius); | ||
7766 | } | ||
7767 | if (nv != null) | ||
7768 | { | ||
7769 | zc.AddBytes(nv, nv.Length); | ||
7770 | } | ||
7771 | |||
7772 | zc.AddByte(part.Shape.PathCurve); | ||
7773 | zc.AddUInt16(part.Shape.PathBegin); | ||
7774 | zc.AddUInt16(part.Shape.PathEnd); | ||
7775 | zc.AddByte(part.Shape.PathScaleX); | ||
7776 | zc.AddByte(pathScaleY); | ||
7777 | zc.AddByte(part.Shape.PathShearX); | ||
7778 | zc.AddByte(part.Shape.PathShearY); | ||
7779 | zc.AddByte((byte)part.Shape.PathTwist); | ||
7780 | zc.AddByte((byte)part.Shape.PathTwistBegin); | ||
7781 | zc.AddByte((byte)part.Shape.PathRadiusOffset); | ||
7782 | zc.AddByte((byte)part.Shape.PathTaperX); | ||
7783 | zc.AddByte((byte)part.Shape.PathTaperY); | ||
7784 | zc.AddByte(part.Shape.PathRevolutions); | ||
7785 | zc.AddByte((byte)part.Shape.PathSkew); | ||
7786 | zc.AddByte(profileCurve); | ||
7787 | zc.AddUInt16(profileBegin); | ||
7788 | zc.AddUInt16(part.Shape.ProfileEnd); | ||
7789 | zc.AddUInt16(profileHollow); | ||
7790 | |||
7791 | if (textureEntry == null) | ||
7792 | { | ||
7793 | zc.AddZeros(4); | ||
7794 | } | ||
7795 | else | ||
7796 | { | ||
7797 | int len = textureEntry.Length; | ||
7798 | zc.AddByte((byte)len); | ||
7799 | zc.AddByte((byte)(len >> 8)); | ||
7800 | zc.AddZeros(2); | ||
7801 | zc.AddBytes(textureEntry, len); | ||
7802 | } | ||
7803 | if (hastexanim) | ||
7804 | { | ||
7805 | byte[] ta = part.TextureAnimation; | ||
7806 | int len = ta.Length; | ||
7807 | zc.AddByte((byte)len); | ||
7808 | zc.AddByte((byte)(len >> 8)); | ||
7809 | zc.AddZeros(2); | ||
7810 | zc.AddBytes(ta, len); | ||
7811 | } | ||
7812 | |||
7813 | if (haspsnew) | ||
7814 | { | ||
7815 | byte[] ps = part.ParticleSystem; | ||
7816 | zc.AddBytes(ps, ps.Length); | ||
7817 | } | ||
7818 | } | ||
7425 | 7819 | ||
7426 | public void SendNameReply(UUID profileId, string firstname, string lastname) | 7820 | public void SendNameReply(UUID profileId, string firstname, string lastname) |
7427 | { | 7821 | { |