diff options
3 files changed, 118 insertions, 27 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index c28e58d..44386c9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -1154,6 +1154,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1154 | 1154 | ||
1155 | /// <summary> | 1155 | /// <summary> |
1156 | /// Send the region heightmap to the client | 1156 | /// Send the region heightmap to the client |
1157 | /// This method is only called when not doing intellegent terrain patch sending and | ||
1158 | /// is only called when the scene presence is initially created and sends all of the | ||
1159 | /// region's patches to the client. | ||
1157 | /// </summary> | 1160 | /// </summary> |
1158 | /// <param name="map">heightmap</param> | 1161 | /// <param name="map">heightmap</param> |
1159 | public virtual void SendLayerData(float[] map) | 1162 | public virtual void SendLayerData(float[] map) |
@@ -1237,9 +1240,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1237 | 1240 | ||
1238 | // Legacy form of invocation that passes around a bare data array. | 1241 | // Legacy form of invocation that passes around a bare data array. |
1239 | // Just ignore what was passed and use the real terrain info that is part of the scene. | 1242 | // Just ignore what was passed and use the real terrain info that is part of the scene. |
1243 | // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI, | ||
1244 | // there is a special form for specifying multiple terrain patches to send. | ||
1245 | // The form is to pass 'px' as negative the number of patches to send and to | ||
1246 | // pass the float array as pairs of patch X and Y coordinates. So, passing 'px' | ||
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>. | ||
1240 | public void SendLayerData(int px, int py, float[] map) | 1249 | public void SendLayerData(int px, int py, float[] map) |
1241 | { | 1250 | { |
1242 | SendLayerData(px, py, m_scene.Heightmap.GetTerrainData()); | 1251 | if (px >= 0) |
1252 | { | ||
1253 | SendLayerData(px, py, m_scene.Heightmap.GetTerrainData()); | ||
1254 | } | ||
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 | } | ||
1265 | |||
1266 | // DebugSendingPatches("SendLayerData", xPatches, yPatches); | ||
1267 | |||
1268 | SendLayerData(xPatches, yPatches, m_scene.Heightmap.GetTerrainData()); | ||
1269 | } | ||
1270 | } | ||
1271 | |||
1272 | private void DebugSendingPatches(string pWho, int[] pX, int[] pY) | ||
1273 | { | ||
1274 | if (m_log.IsDebugEnabled) | ||
1275 | { | ||
1276 | int numPatches = pX.Length; | ||
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); | ||
1285 | } | ||
1243 | } | 1286 | } |
1244 | 1287 | ||
1245 | /// <summary> | 1288 | /// <summary> |
@@ -1252,6 +1295,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1252 | /// <param name="map">heightmap</param> | 1295 | /// <param name="map">heightmap</param> |
1253 | public void SendLayerData(int px, int py, TerrainData terrData) | 1296 | public void SendLayerData(int px, int py, TerrainData terrData) |
1254 | { | 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) | ||
1304 | { | ||
1255 | try | 1305 | try |
1256 | { | 1306 | { |
1257 | /* test code using the terrain compressor in libOpenMetaverse | 1307 | /* test code using the terrain compressor in libOpenMetaverse |
@@ -1259,31 +1309,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1259 | patchInd[0] = px + (py * Constants.TerrainPatchSize); | 1309 | patchInd[0] = px + (py * Constants.TerrainPatchSize); |
1260 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd); | 1310 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd); |
1261 | */ | 1311 | */ |
1262 | LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, px, py); | 1312 | // Many, many patches could have been passed to us. Since the patches will be compressed |
1263 | 1313 | // into variable sized blocks, we cannot pre-compute how many will fit into one | |
1264 | // 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. |
1265 | // 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; |
1266 | // 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) |
1267 | // invalidating previous packets for that area. | 1317 | { |
1268 | 1318 | int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit); | |
1269 | // 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]; |
1270 | // 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]; |
1271 | 1321 | for (int ii = 0; ii < remaining; ii++) | |
1272 | // 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 | { |
1273 | // 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]; |
1274 | // patches. | 1324 | yPatches[ii] = py[pcnt + ii]; |
1325 | } | ||
1326 | LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches); | ||
1327 | // DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches); | ||
1275 | 1328 | ||
1276 | // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. | 1329 | SendTheLayerPacket(layerpack); |
1277 | if (m_justEditedTerrain) | ||
1278 | { | ||
1279 | layerpack.Header.Reliable = false; | ||
1280 | OutPacket(layerpack, ThrottleOutPacketType.Unknown ); | ||
1281 | } | ||
1282 | else | ||
1283 | { | ||
1284 | layerpack.Header.Reliable = true; | ||
1285 | OutPacket(layerpack, ThrottleOutPacketType.Land); | ||
1286 | } | 1330 | } |
1331 | // LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, px, py); | ||
1332 | |||
1287 | } | 1333 | } |
1288 | catch (Exception e) | 1334 | catch (Exception e) |
1289 | { | 1335 | { |
@@ -1291,6 +1337,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1291 | } | 1337 | } |
1292 | } | 1338 | } |
1293 | 1339 | ||
1340 | // When a user edits the terrain, so much data is sent, the data queues up fast and presents a | ||
1341 | // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we | ||
1342 | // start skipping the queues until they're done editing the terrain. We also make them | ||
1343 | // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch | ||
1344 | // area invalidating previous packets for that area. | ||
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) | ||
1357 | { | ||
1358 | if (m_justEditedTerrain) | ||
1359 | { | ||
1360 | layerpack.Header.Reliable = false; | ||
1361 | OutPacket(layerpack, ThrottleOutPacketType.Unknown ); | ||
1362 | } | ||
1363 | else | ||
1364 | { | ||
1365 | layerpack.Header.Reliable = true; | ||
1366 | OutPacket(layerpack, ThrottleOutPacketType.Land); | ||
1367 | } | ||
1368 | } | ||
1369 | |||
1294 | /// <summary> | 1370 | /// <summary> |
1295 | /// Send the wind matrix to the client | 1371 | /// Send the wind matrix to the client |
1296 | /// </summary> | 1372 | /// </summary> |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index c22c5b6..51016c2 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -1035,12 +1035,24 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1035 | // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); | 1035 | // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); |
1036 | // Sort the patches to send by the distance from the presence | 1036 | // Sort the patches to send by the distance from the presence |
1037 | toSend.Sort(); | 1037 | toSend.Sort(); |
1038 | /* | ||
1038 | foreach (PatchesToSend pts in toSend) | 1039 | foreach (PatchesToSend pts in toSend) |
1039 | { | 1040 | { |
1040 | // TODO: one can send multiple patches in a packet. Do that. | ||
1041 | pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); | 1041 | pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); |
1042 | // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); | 1042 | // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); |
1043 | } | 1043 | } |
1044 | */ | ||
1045 | |||
1046 | int[] xPieces = new int[toSend.Count]; | ||
1047 | int[] yPieces = new int[toSend.Count]; | ||
1048 | float[] patchPieces = new float[toSend.Count * 2]; | ||
1049 | int pieceIndex = 0; | ||
1050 | foreach (PatchesToSend pts in toSend) | ||
1051 | { | ||
1052 | patchPieces[pieceIndex++] = pts.PatchX; | ||
1053 | patchPieces[pieceIndex++] = pts.PatchY; | ||
1054 | } | ||
1055 | pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); | ||
1044 | } | 1056 | } |
1045 | } | 1057 | } |
1046 | } | 1058 | } |
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs index 396f1e8..fc8f8cd 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs | |||
@@ -119,6 +119,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
119 | xPieces[0] = patchX; // patch X dimension | 119 | xPieces[0] = patchX; // patch X dimension |
120 | yPieces[0] = patchY; | 120 | yPieces[0] = patchY; |
121 | 121 | ||
122 | return CreateLandPacket(terrData, xPieces, yPieces); | ||
123 | } | ||
124 | |||
125 | public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces) | ||
126 | { | ||
122 | byte landPacketType = (byte)TerrainPatch.LayerType.Land; | 127 | byte landPacketType = (byte)TerrainPatch.LayerType.Land; |
123 | if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) | 128 | if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) |
124 | { | 129 | { |
@@ -148,8 +153,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
148 | /// Array of indexes in the grid of patches. | 153 | /// Array of indexes in the grid of patches. |
149 | /// </param> | 154 | /// </param> |
150 | /// <param name="type"></param> | 155 | /// <param name="type"></param> |
151 | /// <param name="pRegionSizeX"></param> | ||
152 | /// <param name="pRegionSizeY"></param> | ||
153 | /// <returns></returns> | 156 | /// <returns></returns> |
154 | public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type) | 157 | public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type) |
155 | { | 158 | { |