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