diff options
author | UbitUmarov | 2019-03-14 17:11:23 +0000 |
---|---|---|
committer | UbitUmarov | 2019-03-14 17:11:23 +0000 |
commit | f143dbc23fc5984728d32602f9602a4fcda35577 (patch) | |
tree | e93370398d31df5a33edbe4a2964f582893aa544 /OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |
parent | Robust: to tell main httpserver to stop on shutdown (diff) | |
download | opensim-SC-f143dbc23fc5984728d32602f9602a4fcda35577.zip opensim-SC-f143dbc23fc5984728d32602f9602a4fcda35577.tar.gz opensim-SC-f143dbc23fc5984728d32602f9602a4fcda35577.tar.bz2 opensim-SC-f143dbc23fc5984728d32602f9602a4fcda35577.tar.xz |
lludp direct encode object Properties update packets
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 327 |
1 files changed, 199 insertions, 128 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index ac041f5..181c4e2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -5121,14 +5121,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5121 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); | 5121 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); |
5122 | } | 5122 | } |
5123 | 5123 | ||
5124 | static private readonly byte[] ObjectPropertyUpdateHeader = new byte[] { | ||
5125 | Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, | ||
5126 | 0, 0, 0, 0, // sequence number | ||
5127 | 0, // extra | ||
5128 | 0xff, 9 // ID (medium frequency) | ||
5129 | }; | ||
5130 | |||
5131 | static private readonly byte[] ObjectFamilyUpdateHeader = new byte[] { | ||
5132 | Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, | ||
5133 | 0, 0, 0, 0, // sequence number | ||
5134 | 0, // extra | ||
5135 | 0xff, 10 // ID (medium frequency) | ||
5136 | }; | ||
5137 | |||
5124 | private void ProcessEntityPropertyRequests(int maxUpdateBytes) | 5138 | private void ProcessEntityPropertyRequests(int maxUpdateBytes) |
5125 | { | 5139 | { |
5126 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> objectFamilyBlocks = null; | 5140 | List<ObjectPropertyUpdate> objectPropertiesUpdates = null; |
5127 | List<ObjectPropertiesPacket.ObjectDataBlock> objectPropertiesBlocks = null; | 5141 | List<ObjectPropertyUpdate> objectPropertiesFamilyUpdates = null; |
5128 | List<SceneObjectPart> needPhysics = null; | 5142 | List<SceneObjectPart> needPhysics = null; |
5129 | 5143 | ||
5130 | bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; | 5144 | // bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; |
5131 | 5145 | bool orderedDequeue = false; // for now | |
5132 | EntityUpdate iupdate; | 5146 | EntityUpdate iupdate; |
5133 | 5147 | ||
5134 | while (maxUpdateBytes > 0) | 5148 | while (maxUpdateBytes > 0) |
@@ -5153,11 +5167,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5153 | if (update.Entity is SceneObjectPart) | 5167 | if (update.Entity is SceneObjectPart) |
5154 | { | 5168 | { |
5155 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | 5169 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
5156 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); | 5170 | if(objectPropertiesFamilyUpdates == null) |
5157 | if(objectFamilyBlocks == null) | 5171 | objectPropertiesFamilyUpdates = new List<ObjectPropertyUpdate>(); |
5158 | objectFamilyBlocks = new List<ObjectPropertiesFamilyPacket.ObjectDataBlock>(); | 5172 | objectPropertiesFamilyUpdates.Add(update); |
5159 | objectFamilyBlocks.Add(objPropDB); | 5173 | maxUpdateBytes -= 100; |
5160 | maxUpdateBytes -= objPropDB.Length; | ||
5161 | } | 5174 | } |
5162 | } | 5175 | } |
5163 | 5176 | ||
@@ -5169,58 +5182,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5169 | if(needPhysics == null) | 5182 | if(needPhysics == null) |
5170 | needPhysics = new List<SceneObjectPart>(); | 5183 | needPhysics = new List<SceneObjectPart>(); |
5171 | needPhysics.Add(sop); | 5184 | needPhysics.Add(sop); |
5172 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); | 5185 | if(objectPropertiesUpdates == null) |
5173 | if(objectPropertiesBlocks == null) | 5186 | objectPropertiesUpdates = new List<ObjectPropertyUpdate>(); |
5174 | objectPropertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>(); | 5187 | objectPropertiesUpdates.Add(update); |
5175 | objectPropertiesBlocks.Add(objPropDB); | 5188 | maxUpdateBytes -= 200; // aprox |
5176 | maxUpdateBytes -= objPropDB.Length; | ||
5177 | } | 5189 | } |
5178 | } | 5190 | } |
5179 | } | 5191 | } |
5180 | 5192 | ||
5181 | if (objectPropertiesBlocks != null) | 5193 | if (objectPropertiesUpdates != null) |
5182 | { | 5194 | { |
5183 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 5195 | int blocks = objectPropertiesUpdates.Count; |
5184 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count]; | 5196 | //List<EntityUpdate> tau = new List<EntityUpdate>(30); |
5185 | for (int i = 0; i < objectPropertiesBlocks.Count; i++) | ||
5186 | packet.ObjectData[i] = objectPropertiesBlocks[i]; | ||
5187 | 5197 | ||
5188 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties | 5198 | UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); |
5189 | // of the object rather than the properties when the packet was created | 5199 | Buffer.BlockCopy(ObjectPropertyUpdateHeader, 0, buf.Data, 0, 8); |
5190 | // HACK : Remove intelligent resending until it's fixed in core | 5200 | |
5191 | //OutPacket(packet, ThrottleOutPacketType.Task, true, | 5201 | LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); |
5192 | // delegate(OutgoingPacket oPacket) | 5202 | zc.Position = 8; |
5193 | // { | 5203 | |
5194 | // ResendPropertyUpdates(propertyUpdates.Value, oPacket); | 5204 | zc.AddByte(1); // tmp block count |
5195 | // }); | 5205 | |
5196 | OutPacket(packet, ThrottleOutPacketType.Task, true); | 5206 | int countposition = zc.Position - 1; |
5207 | |||
5208 | int lastpos = 0; | ||
5209 | int lastzc = 0; | ||
5210 | |||
5211 | int count = 0; | ||
5212 | foreach (EntityUpdate eu in objectPropertiesUpdates) | ||
5213 | { | ||
5214 | lastpos = zc.Position; | ||
5215 | lastzc = zc.ZeroCount; | ||
5216 | CreateObjectPropertiesBlock((SceneObjectPart)eu.Entity, zc); | ||
5217 | if (zc.Position < LLUDPServer.MAXPAYLOAD) | ||
5218 | { | ||
5219 | //tau.Add(eu); | ||
5220 | ++count; | ||
5221 | --blocks; | ||
5222 | } | ||
5223 | else if (blocks > 0) | ||
5224 | { | ||
5225 | // we need more packets | ||
5226 | UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); | ||
5227 | Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same | ||
5228 | |||
5229 | buf.Data[countposition] = (byte)count; | ||
5230 | // get pending zeros at cut point | ||
5231 | if (lastzc > 0) | ||
5232 | { | ||
5233 | buf.Data[lastpos++] = 0; | ||
5234 | buf.Data[lastpos++] = (byte)lastzc; | ||
5235 | } | ||
5236 | buf.DataLength = lastpos; | ||
5237 | |||
5238 | //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, | ||
5239 | // delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); | ||
5240 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, false); | ||
5241 | buf = newbuf; | ||
5242 | zc.Data = buf.Data; | ||
5243 | zc.ZeroCount = 0; | ||
5244 | zc.Position = countposition + 1; | ||
5245 | // im lazy now, just do last again | ||
5246 | CreateObjectPropertiesBlock((SceneObjectPart)eu.Entity, zc); | ||
5247 | |||
5248 | //tau = new List<EntityUpdate>(30); | ||
5249 | //tau.Add(eu); | ||
5250 | count = 1; | ||
5251 | --blocks; | ||
5252 | } | ||
5253 | } | ||
5254 | |||
5255 | if (count > 0) | ||
5256 | { | ||
5257 | buf.Data[countposition] = (byte)count; | ||
5258 | buf.DataLength = zc.Finish(); | ||
5259 | //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, | ||
5260 | // delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); | ||
5261 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, false); | ||
5262 | } | ||
5197 | } | 5263 | } |
5198 | 5264 | ||
5199 | if (objectFamilyBlocks != null) | 5265 | if (objectPropertiesFamilyUpdates != null) |
5200 | { | 5266 | { |
5201 | // one packet per object block... uggh... | 5267 | foreach (EntityUpdate eu in objectPropertiesFamilyUpdates) |
5202 | for (int i = 0; i < objectFamilyBlocks.Count; i++) | ||
5203 | { | 5268 | { |
5204 | ObjectPropertiesFamilyPacket packet = | 5269 | UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); |
5205 | (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); | 5270 | Buffer.BlockCopy(ObjectFamilyUpdateHeader, 0, buf.Data, 0, 8); |
5206 | 5271 | ||
5207 | packet.ObjectData = objectFamilyBlocks[i]; | 5272 | LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); |
5273 | zc.Position = 8; | ||
5208 | 5274 | ||
5209 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties | 5275 | CreateObjectPropertiesFamilyBlock((SceneObjectPart)eu.Entity, eu.Flags, zc); |
5210 | // of the object rather than the properties when the packet was created | 5276 | buf.DataLength = zc.Finish(); |
5211 | // List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); | 5277 | //List<EntityUpdate> tau = new List<EntityUpdate>(1); |
5212 | // updates.Add(familyUpdates.Value[i]); | 5278 | //tau.Add(new ObjectPropertyUpdate((ISceneEntity) eu, (uint)eu.Flags, true, false)); |
5213 | // HACK : Remove intelligent resending until it's fixed in core | 5279 | //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, |
5214 | //OutPacket(packet, ThrottleOutPacketType.Task, true, | 5280 | // delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); |
5215 | // delegate(OutgoingPacket oPacket) | 5281 | m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, false); |
5216 | // { | ||
5217 | // ResendPropertyUpdates(updates, oPacket); | ||
5218 | // }); | ||
5219 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
5220 | } | 5282 | } |
5221 | } | 5283 | } |
5222 | 5284 | ||
5223 | if(needPhysics != null) | 5285 | if (needPhysics != null) |
5224 | { | 5286 | { |
5225 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | 5287 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); |
5226 | if(eq != null) | 5288 | if(eq != null) |
@@ -5245,101 +5307,110 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5245 | } | 5307 | } |
5246 | } | 5308 | } |
5247 | 5309 | ||
5248 | private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, PrimUpdateFlags requestFlags) | 5310 | private void CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, PrimUpdateFlags requestFlags, LLUDPZeroEncoder zc) |
5249 | { | 5311 | { |
5250 | ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); | 5312 | SceneObjectPart root = sop.ParentGroup.RootPart; |
5251 | 5313 | ||
5252 | block.RequestFlags = (uint)requestFlags; | 5314 | zc.AddUInt((uint)requestFlags); |
5253 | block.ObjectID = sop.UUID; | 5315 | zc.AddUUID(sop.UUID); |
5254 | if (sop.OwnerID == sop.GroupID) | 5316 | if (sop.OwnerID == sop.GroupID) |
5255 | block.OwnerID = UUID.Zero; | 5317 | zc.AddZeros(16); |
5256 | else | 5318 | else |
5257 | block.OwnerID = sop.OwnerID; | 5319 | zc.AddUUID(sop.OwnerID); |
5258 | block.GroupID = sop.GroupID; | 5320 | zc.AddUUID(sop.GroupID); |
5259 | block.BaseMask = sop.BaseMask; | ||
5260 | block.OwnerMask = sop.OwnerMask; | ||
5261 | block.GroupMask = sop.GroupMask; | ||
5262 | block.EveryoneMask = sop.EveryoneMask; | ||
5263 | block.NextOwnerMask = sop.NextOwnerMask; | ||
5264 | |||
5265 | // TODO: More properties are needed in SceneObjectPart! | ||
5266 | block.OwnershipCost = sop.OwnershipCost; | ||
5267 | block.SaleType = sop.ObjectSaleType; | ||
5268 | block.SalePrice = sop.SalePrice; | ||
5269 | block.Category = sop.Category; | ||
5270 | block.LastOwnerID = sop.LastOwnerID; | ||
5271 | block.Name = Util.StringToBytes256(sop.Name); | ||
5272 | block.Description = Util.StringToBytes256(sop.Description); | ||
5273 | 5321 | ||
5274 | return block; | 5322 | zc.AddUInt(root.BaseMask); |
5275 | } | 5323 | zc.AddUInt(root.OwnerMask); |
5324 | zc.AddUInt(root.GroupMask); | ||
5325 | zc.AddUInt(root.EveryoneMask); | ||
5326 | zc.AddUInt(root.NextOwnerMask); | ||
5276 | 5327 | ||
5277 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) | 5328 | zc.AddZeros(4); // int ownership cost |
5278 | { | ||
5279 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | ||
5280 | // TODO: don't create new blocks if recycling an old packet | ||
5281 | 5329 | ||
5282 | ObjectPropertiesPacket.ObjectDataBlock block = | 5330 | //sale info block |
5283 | new ObjectPropertiesPacket.ObjectDataBlock(); | 5331 | zc.AddByte(root.ObjectSaleType); |
5332 | zc.AddInt(root.SalePrice); | ||
5284 | 5333 | ||
5285 | block.ObjectID = sop.UUID; | 5334 | zc.AddUInt(sop.Category); //Category |
5286 | block.Name = Util.StringToBytes256(sop.Name); | ||
5287 | block.Description = Util.StringToBytes256(sop.Description); | ||
5288 | 5335 | ||
5289 | block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds | 5336 | zc.AddUUID(sop.LastOwnerID); |
5290 | block.CreatorID = sop.CreatorID; | ||
5291 | block.GroupID = sop.GroupID; | ||
5292 | block.LastOwnerID = sop.LastOwnerID; | ||
5293 | if (sop.OwnerID == sop.GroupID) | ||
5294 | block.OwnerID = UUID.Zero; | ||
5295 | else | ||
5296 | block.OwnerID = sop.OwnerID; | ||
5297 | 5337 | ||
5298 | block.ItemID = sop.FromUserInventoryItemID; | 5338 | //name |
5299 | block.FolderID = UUID.Zero; // sog.FromFolderID ?? | 5339 | byte[] tmpbytes = Util.StringToBytes256(sop.Name); |
5300 | block.FromTaskID = UUID.Zero; // ??? | 5340 | zc.AddByte((byte)tmpbytes.Length); |
5301 | block.InventorySerial = (short)sop.InventorySerial; | 5341 | zc.AddBytes(tmpbytes, tmpbytes.Length); |
5302 | 5342 | ||
5303 | SceneObjectPart root = sop.ParentGroup.RootPart; | 5343 | //Description |
5304 | 5344 | tmpbytes = Util.StringToBytes256(sop.Description); | |
5305 | block.TouchName = Util.StringToBytes256(root.TouchName); | 5345 | zc.AddByte((byte)tmpbytes.Length); |
5346 | zc.AddBytes(tmpbytes, tmpbytes.Length); | ||
5347 | } | ||
5306 | 5348 | ||
5307 | // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but | 5349 | private void CreateObjectPropertiesBlock(SceneObjectPart sop, LLUDPZeroEncoder zc) |
5308 | // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached | 5350 | { |
5309 | // copy is really needed since it's less efficient to be constantly recreating this byte array. | 5351 | SceneObjectPart root = sop.ParentGroup.RootPart; |
5310 | // using (MemoryStream memStream = new MemoryStream()) | ||
5311 | // { | ||
5312 | // using (BinaryWriter binWriter = new BinaryWriter(memStream)) | ||
5313 | // { | ||
5314 | // for (int i = 0; i < sop.GetNumberOfSides(); i++) | ||
5315 | // { | ||
5316 | // Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; | ||
5317 | // | ||
5318 | // UUID textureID; | ||
5319 | // | ||
5320 | // if (teFace != null) | ||
5321 | // textureID = teFace.TextureID; | ||
5322 | // else | ||
5323 | // textureID = sop.Shape.Textures.DefaultTexture.TextureID; | ||
5324 | // | ||
5325 | // binWriter.Write(textureID.GetBytes()); | ||
5326 | // } | ||
5327 | // | ||
5328 | // block.TextureID = memStream.ToArray(); | ||
5329 | // } | ||
5330 | // } | ||
5331 | |||
5332 | block.TextureID = new byte[0]; // TextureID ??? | ||
5333 | block.SitName = Util.StringToBytes256(root.SitName); | ||
5334 | block.OwnerMask = root.OwnerMask; | ||
5335 | block.NextOwnerMask = root.NextOwnerMask; | ||
5336 | block.GroupMask = root.GroupMask; | ||
5337 | block.EveryoneMask = root.EveryoneMask; | ||
5338 | block.BaseMask = root.BaseMask; | ||
5339 | block.SaleType = root.ObjectSaleType; | ||
5340 | block.SalePrice = root.SalePrice; | ||
5341 | 5352 | ||
5342 | return block; | 5353 | zc.AddUUID(sop.UUID); |
5354 | zc.AddUUID(sop.CreatorID); | ||
5355 | if (sop.OwnerID == sop.GroupID) | ||
5356 | zc.AddZeros(16); | ||
5357 | else | ||
5358 | zc.AddUUID(sop.OwnerID); | ||
5359 | zc.AddUUID(sop.GroupID); | ||
5360 | |||
5361 | zc.AddUInt64((ulong)sop.CreationDate * 1000000UL); | ||
5362 | |||
5363 | zc.AddUInt(root.BaseMask); | ||
5364 | zc.AddUInt(root.OwnerMask); | ||
5365 | zc.AddUInt(root.GroupMask); | ||
5366 | zc.AddUInt(root.EveryoneMask); | ||
5367 | zc.AddUInt(root.NextOwnerMask); | ||
5368 | |||
5369 | zc.AddZeros(4); // int ownership cost | ||
5370 | |||
5371 | //sale info block | ||
5372 | zc.AddByte(root.ObjectSaleType); | ||
5373 | zc.AddInt(root.SalePrice); | ||
5374 | |||
5375 | //aggregated perms we may will need to fix this | ||
5376 | zc.AddByte(0); //AggregatePerms | ||
5377 | zc.AddByte(0); //AggregatePermTextures; | ||
5378 | zc.AddByte(0); //AggregatePermTexturesOwner | ||
5379 | |||
5380 | //inventory info | ||
5381 | zc.AddUInt(sop.Category); //Category | ||
5382 | zc.AddInt16((short)sop.InventorySerial); | ||
5383 | zc.AddUUID(sop.FromUserInventoryItemID); | ||
5384 | zc.AddUUID(UUID.Zero); //FolderID | ||
5385 | zc.AddUUID(UUID.Zero); //FromTaskID | ||
5386 | |||
5387 | zc.AddUUID(sop.LastOwnerID); | ||
5388 | |||
5389 | //name | ||
5390 | byte[] tmpbytes = Util.StringToBytes256(sop.Name); | ||
5391 | zc.AddByte((byte)tmpbytes.Length); | ||
5392 | zc.AddBytes(tmpbytes, tmpbytes.Length); | ||
5393 | |||
5394 | //Description | ||
5395 | tmpbytes = Util.StringToBytes256(sop.Description); | ||
5396 | zc.AddByte((byte)tmpbytes.Length); | ||
5397 | zc.AddBytes(tmpbytes, tmpbytes.Length); | ||
5398 | |||
5399 | // touch name | ||
5400 | tmpbytes = Util.StringToBytes256(root.TouchName); | ||
5401 | zc.AddByte((byte)tmpbytes.Length); | ||
5402 | zc.AddBytes(tmpbytes, tmpbytes.Length); | ||
5403 | |||
5404 | // sit name | ||
5405 | tmpbytes = Util.StringToBytes256(root.SitName); | ||
5406 | zc.AddByte((byte)tmpbytes.Length); | ||
5407 | zc.AddBytes(tmpbytes, tmpbytes.Length); | ||
5408 | |||
5409 | //texture ids block | ||
5410 | // still not sending, not clear the impact on viewers, if any. | ||
5411 | // does seem redundant | ||
5412 | // to send we will need proper list of face texture ids without having to unpack texture entry all the time | ||
5413 | zc.AddZeros(1); | ||
5343 | } | 5414 | } |
5344 | 5415 | ||
5345 | #region Estate Data Sending Methods | 5416 | #region Estate Data Sending Methods |