aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs124
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainCompressor.cs7
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 {