aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs273
1 files changed, 164 insertions, 109 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 7b6889a..226f2a1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -312,6 +312,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
312 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; 312 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
313 313
314 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 314 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
315 private static string LogHeader = "[LLCLIENTVIEW]";
315 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients 316 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
316 317
317 /// <summary> 318 /// <summary>
@@ -692,12 +693,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
692 /// <returns>true if the handler was added. This is currently always the case.</returns> 693 /// <returns>true if the handler was added. This is currently always the case.</returns>
693 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) 694 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
694 { 695 {
696 return AddLocalPacketHandler(packetType, handler, doAsync, false);
697 }
698
699 /// <summary>
700 /// Add a handler for the given packet type.
701 /// </summary>
702 /// <param name="packetType"></param>
703 /// <param name="handler"></param>
704 /// <param name="doAsync">
705 /// If true, when the packet is received handle it on a different thread. Whether this is given direct to
706 /// a threadpool thread or placed in a queue depends on the inEngine parameter.
707 /// </param>
708 /// <param name="inEngine">
709 /// If async is false then this parameter is ignored.
710 /// If async is true and inEngine is false, then the packet is sent directly to a
711 /// threadpool thread.
712 /// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine.
713 /// This may result in slower handling but reduces the risk of overloading the simulator when there are many
714 /// simultaneous async requests.
715 /// </param>
716 /// <returns>true if the handler was added. This is currently always the case.</returns>
717 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine)
718 {
695 bool result = false; 719 bool result = false;
696 lock (m_packetHandlers) 720 lock (m_packetHandlers)
697 { 721 {
698 if (!m_packetHandlers.ContainsKey(packetType)) 722 if (!m_packetHandlers.ContainsKey(packetType))
699 { 723 {
700 m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = doAsync }); 724 m_packetHandlers.Add(
725 packetType, new PacketProcessor() { method = handler, Async = doAsync });
701 result = true; 726 result = true;
702 } 727 }
703 } 728 }
@@ -1176,11 +1201,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1176 1201
1177 /// <summary> 1202 /// <summary>
1178 /// Send the region heightmap to the client 1203 /// Send the region heightmap to the client
1204 /// This method is only called when not doing intellegent terrain patch sending and
1205 /// is only called when the scene presence is initially created and sends all of the
1206 /// region's patches to the client.
1179 /// </summary> 1207 /// </summary>
1180 /// <param name="map">heightmap</param> 1208 /// <param name="map">heightmap</param>
1181 public virtual void SendLayerData(float[] map) 1209 public virtual void SendLayerData(float[] map)
1182 { 1210 {
1183 Util.FireAndForget(DoSendLayerData, map); 1211 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData());
1184 1212
1185 // Send it sync, and async. It's not that much data 1213 // Send it sync, and async. It's not that much data
1186 // and it improves user experience just so much! 1214 // and it improves user experience just so much!
@@ -1193,15 +1221,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1193 /// <param name="o"></param> 1221 /// <param name="o"></param>
1194 private void DoSendLayerData(object o) 1222 private void DoSendLayerData(object o)
1195 { 1223 {
1196 float[] map = LLHeightFieldMoronize((float[])o); 1224 TerrainData map = (TerrainData)o;
1197 1225
1198 try 1226 try
1199 { 1227 {
1228 // Send LayerData in typerwriter pattern
1200 for (int y = 0; y < 16; y++) 1229 for (int y = 0; y < 16; y++)
1201 { 1230 {
1202 for (int x = 0; x < 16; x+=4) 1231 for (int x = 0; x < 16; x++)
1203 { 1232 {
1204 SendLayerPacket(x, y, map); 1233 SendLayerData(x, y, map);
1205 } 1234 }
1206 } 1235 }
1207 } 1236 }
@@ -1211,77 +1240,95 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 } 1240 }
1212 } 1241 }
1213 1242
1214 /// <summary> 1243 // Legacy form of invocation that passes around a bare data array.
1215 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1244 // Just ignore what was passed and use the real terrain info that is part of the scene.
1216 /// </summary> 1245 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
1217 /// <param name="map">heightmap</param> 1246 // there is a special form for specifying multiple terrain patches to send.
1218 /// <param name="px">X coordinate for patches 0..12</param> 1247 // The form is to pass 'px' as negative the number of patches to send and to
1219 /// <param name="py">Y coordinate for patches 0..15</param> 1248 // pass the float array as pairs of patch X and Y coordinates. So, passing 'px'
1220 private void SendLayerPacket(int x, int y, float[] map) 1249 // as -2 and map= [3, 5, 8, 4] would mean to send two terrain heightmap patches
1250 // and the patches to send are <3,5> and <8,4>.
1251 public void SendLayerData(int px, int py, float[] map)
1221 { 1252 {
1222 int[] patches = new int[4]; 1253 if (px >= 0)
1223 patches[0] = x + 0 + y * 16; 1254 {
1224 patches[1] = x + 1 + y * 16; 1255 SendLayerData(px, py, m_scene.Heightmap.GetTerrainData());
1225 patches[2] = x + 2 + y * 16; 1256 }
1226 patches[3] = x + 3 + y * 16; 1257 else
1258 {
1259 int numPatches = -px;
1260 int[] xPatches = new int[numPatches];
1261 int[] yPatches = new int[numPatches];
1262 for (int pp = 0; pp < numPatches; pp++)
1263 {
1264 xPatches[pp] = (int)map[pp * 2];
1265 yPatches[pp] = (int)map[pp * 2 + 1];
1266 }
1227 1267
1228 float[] heightmap = (map.Length == 65536) ? 1268 // DebugSendingPatches("SendLayerData", xPatches, yPatches);
1229 map :
1230 LLHeightFieldMoronize(map);
1231 1269
1232 try 1270 SendLayerData(xPatches, yPatches, m_scene.Heightmap.GetTerrainData());
1233 {
1234 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1235 OutPacket(layerpack, ThrottleOutPacketType.Land);
1236 } 1271 }
1237 catch 1272 }
1273
1274 private void DebugSendingPatches(string pWho, int[] pX, int[] pY)
1275 {
1276 if (m_log.IsDebugEnabled)
1238 { 1277 {
1239 for (int px = x ; px < x + 4 ; px++) 1278 int numPatches = pX.Length;
1240 SendLayerData(px, y, map); 1279 string Xs = "";
1280 string Ys = "";
1281 for (int pp = 0; pp < numPatches; pp++)
1282 {
1283 Xs += String.Format("{0}", (int)pX[pp]) + ",";
1284 Ys += String.Format("{0}", (int)pY[pp]) + ",";
1285 }
1286 m_log.DebugFormat("{0} {1}: numPatches={2}, X={3}, Y={4}", LogHeader, pWho, numPatches, Xs, Ys);
1241 } 1287 }
1242 } 1288 }
1243 1289
1244 /// <summary> 1290 /// <summary>
1245 /// Sends a specified patch to a client 1291 /// Sends a terrain packet for the point specified.
1292 /// This is a legacy call that has refarbed the terrain into a flat map of floats.
1293 /// We just use the terrain from the region we know about.
1246 /// </summary> 1294 /// </summary>
1247 /// <param name="px">Patch coordinate (x) 0..15</param> 1295 /// <param name="px">Patch coordinate (x) 0..15</param>
1248 /// <param name="py">Patch coordinate (y) 0..15</param> 1296 /// <param name="py">Patch coordinate (y) 0..15</param>
1249 /// <param name="map">heightmap</param> 1297 /// <param name="map">heightmap</param>
1250 public void SendLayerData(int px, int py, float[] map) 1298 public void SendLayerData(int px, int py, TerrainData terrData)
1299 {
1300 int[] xPatches = new[] { px };
1301 int[] yPatches = new[] { py };
1302 SendLayerData(xPatches, yPatches, terrData);
1303 }
1304
1305 private void SendLayerData(int[] px, int[] py, TerrainData terrData)
1251 { 1306 {
1252 try 1307 try
1253 { 1308 {
1254 int[] patches = new int[] { py * 16 + px }; 1309 /* test code using the terrain compressor in libOpenMetaverse
1255 float[] heightmap = (map.Length == 65536) ? 1310 int[] patchInd = new int[1];
1256 map : 1311 patchInd[0] = px + (py * Constants.TerrainPatchSize);
1257 LLHeightFieldMoronize(map); 1312 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd);
1258 1313 */
1259 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1314 // Many, many patches could have been passed to us. Since the patches will be compressed
1260 1315 // into variable sized blocks, we cannot pre-compute how many will fit into one
1261 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. 1316 // packet. While some fancy packing algorithm is possible, 4 seems to always fit.
1262 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. 1317 int PatchesAssumedToFit = 4;
1263 // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area 1318 for (int pcnt = 0; pcnt < px.Length; pcnt += PatchesAssumedToFit)
1264 // invalidating previous packets for that area. 1319 {
1265 1320 int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit);
1266 // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a 1321 int[] xPatches = new int[remaining];
1267 // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower. 1322 int[] yPatches = new int[remaining];
1268 1323 for (int ii = 0; ii < remaining; ii++)
1269 // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will 1324 {
1270 // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain 1325 xPatches[ii] = px[pcnt + ii];
1271 // patches. 1326 yPatches[ii] = py[pcnt + ii];
1327 }
1328 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches);
1329 // DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches);
1272 1330
1273 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. 1331 SendTheLayerPacket(layerpack);
1274 if (m_justEditedTerrain)
1275 {
1276 layerpack.Header.Reliable = false;
1277 OutPacket(layerpack,
1278 ThrottleOutPacketType.Unknown );
1279 }
1280 else
1281 {
1282 layerpack.Header.Reliable = true;
1283 OutPacket(layerpack,
1284 ThrottleOutPacketType.Task);
1285 } 1332 }
1286 } 1333 }
1287 catch (Exception e) 1334 catch (Exception e)
@@ -1290,36 +1337,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1290 } 1337 }
1291 } 1338 }
1292 1339
1293 /// <summary> 1340 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a
1294 /// Munges heightfield into the LLUDP backed in restricted heightfield. 1341 // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we
1295 /// </summary> 1342 // start skipping the queues until they're done editing the terrain. We also make them
1296 /// <param name="map">float array in the base; Constants.RegionSize</param> 1343 // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch
1297 /// <returns>float array in the base 256</returns> 1344 // area invalidating previous packets for that area.
1298 internal float[] LLHeightFieldMoronize(float[] map) 1345
1346 // It's possible for an editing user to flood themselves with edited packets but the majority
1347 // of use cases are such that only a tiny percentage of users will be editing the terrain.
1348 // Other, non-editing users will see the edits much slower.
1349
1350 // One last note on this topic, by the time users are going to be editing the terrain, it's
1351 // extremely likely that the sim will have rezzed already and therefore this is not likely going
1352 // to cause any additional issues with lost packets, objects or terrain patches.
1353
1354 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we
1355 // only have one cache miss.
1356 private void SendTheLayerPacket(LayerDataPacket layerpack)
1299 { 1357 {
1300 if (map.Length == 65536) 1358 if (m_justEditedTerrain)
1301 return map; 1359 {
1360 layerpack.Header.Reliable = false;
1361 OutPacket(layerpack, ThrottleOutPacketType.Unknown );
1362 }
1302 else 1363 else
1303 { 1364 {
1304 float[] returnmap = new float[65536]; 1365 layerpack.Header.Reliable = true;
1305 1366 OutPacket(layerpack, ThrottleOutPacketType.Land);
1306 if (map.Length < 65535)
1307 {
1308 // rebase the vector stride to 256
1309 for (int i = 0; i < Constants.RegionSize; i++)
1310 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, (int)Constants.RegionSize);
1311 }
1312 else
1313 {
1314 for (int i = 0; i < 256; i++)
1315 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256);
1316 }
1317
1318 //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536);
1319
1320 return returnmap;
1321 } 1367 }
1322
1323 } 1368 }
1324 1369
1325 /// <summary> 1370 /// <summary>
@@ -1348,21 +1393,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1348 { 1393 {
1349 Vector2[] windSpeeds = (Vector2[])o; 1394 Vector2[] windSpeeds = (Vector2[])o;
1350 TerrainPatch[] patches = new TerrainPatch[2]; 1395 TerrainPatch[] patches = new TerrainPatch[2];
1351 patches[0] = new TerrainPatch(); 1396 patches[0] = new TerrainPatch { Data = new float[16 * 16] };
1352 patches[0].Data = new float[16 * 16]; 1397 patches[1] = new TerrainPatch { Data = new float[16 * 16] };
1353 patches[1] = new TerrainPatch();
1354 patches[1].Data = new float[16 * 16];
1355 1398
1356 for (int y = 0; y < 16; y++) 1399 for (int x = 0; x < 16 * 16; x++)
1357 { 1400 {
1358 for (int x = 0; x < 16; x++) 1401 patches[0].Data[x] = windSpeeds[x].X;
1359 { 1402 patches[1].Data[x] = windSpeeds[x].Y;
1360 patches[0].Data[y * 16 + x] = windSpeeds[y * 16 + x].X;
1361 patches[1].Data[y * 16 + x] = windSpeeds[y * 16 + x].Y;
1362 }
1363 } 1403 }
1364 1404
1365 LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Wind); 1405 byte layerType = (byte)TerrainPatch.LayerType.Wind;
1406 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1407 layerType = (byte)TerrainPatch.LayerType.WindExtended;
1408
1409 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1410 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1411 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1366 layerpack.Header.Zerocoded = true; 1412 layerpack.Header.Zerocoded = true;
1367 OutPacket(layerpack, ThrottleOutPacketType.Wind); 1413 OutPacket(layerpack, ThrottleOutPacketType.Wind);
1368 } 1414 }
@@ -1386,7 +1432,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1386 } 1432 }
1387 } 1433 }
1388 1434
1389 LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Cloud); 1435 byte layerType = (byte)TerrainPatch.LayerType.Cloud;
1436 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1437 layerType = (byte)TerrainPatch.LayerType.CloudExtended;
1438
1439 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1440 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1441 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1390 layerpack.Header.Zerocoded = true; 1442 layerpack.Header.Zerocoded = true;
1391 OutPacket(layerpack, ThrottleOutPacketType.Cloud); 1443 OutPacket(layerpack, ThrottleOutPacketType.Cloud);
1392 } 1444 }
@@ -1491,10 +1543,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1491 mapReply.Data[i].Access = mapBlocks2[i].Access; 1543 mapReply.Data[i].Access = mapBlocks2[i].Access;
1492 mapReply.Data[i].Agents = mapBlocks2[i].Agents; 1544 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1493 1545
1494 // TODO: hookup varregion sim size here
1495 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock(); 1546 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1496 mapReply.Size[i].SizeX = 256; 1547 mapReply.Size[i].SizeX = mapBlocks2[i].SizeX;
1497 mapReply.Size[i].SizeY = 256; 1548 mapReply.Size[i].SizeY = mapBlocks2[i].SizeY;
1498 } 1549 }
1499 OutPacket(mapReply, ThrottleOutPacketType.Land); 1550 OutPacket(mapReply, ThrottleOutPacketType.Land);
1500 } 1551 }
@@ -1659,15 +1710,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1659 1710
1660 public void SendKillObject(List<uint> localIDs) 1711 public void SendKillObject(List<uint> localIDs)
1661 { 1712 {
1662// foreach (uint id in localIDs)
1663// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1664
1665 // remove pending entities
1666 lock (m_entityProps.SyncRoot)
1667 m_entityProps.Remove(localIDs);
1668 lock (m_entityUpdates.SyncRoot)
1669 m_entityUpdates.Remove(localIDs);
1670
1671 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1713 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1672 // TODO: don't create new blocks if recycling an old packet 1714 // TODO: don't create new blocks if recycling an old packet
1673 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; 1715 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
@@ -9093,6 +9135,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9093 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest; 9135 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest;
9094 if (handlerTeleportLocationRequest != null) 9136 if (handlerTeleportLocationRequest != null)
9095 { 9137 {
9138 // Adjust teleport location to base of a larger region if requested to teleport to a sub-region
9139 uint locX, locY;
9140 Util.RegionHandleToWorldLoc(tpLocReq.Info.RegionHandle, out locX, out locY);
9141 if ((locX >= m_scene.RegionInfo.WorldLocX)
9142 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
9143 && (locY >= m_scene.RegionInfo.WorldLocY)
9144 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) )
9145 {
9146 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
9147 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
9148 tpLocReq.Info.Position.Y += locY - m_scene.RegionInfo.WorldLocY;
9149 }
9150
9096 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position, 9151 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position,
9097 tpLocReq.Info.LookAt, 16); 9152 tpLocReq.Info.LookAt, 16);
9098 } 9153 }