diff options
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 47 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | 198 |
2 files changed, 189 insertions, 56 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 6df55a6..7c5aee7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -1242,14 +1242,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1242 | try | 1242 | try |
1243 | { | 1243 | { |
1244 | // Send LayerData in typerwriter pattern | 1244 | // Send LayerData in typerwriter pattern |
1245 | //for (int y = 0; y < 16; y++) | ||
1246 | //{ | ||
1247 | // for (int x = 0; x < 16; x++) | ||
1248 | // { | ||
1249 | // SendLayerData(x, y, map); | ||
1250 | // } | ||
1251 | //} | ||
1245 | 1252 | ||
1246 | for (int y = 0; y < 16; y++) | 1253 | // Send LayerData in a spiral pattern. Fun! |
1247 | { | 1254 | SendLayerTopRight(map, 0, 0, map.SizeX / Constants.TerrainPatchSize - 1, map.SizeY / Constants.TerrainPatchSize - 1); |
1248 | for (int x = 0; x < 16; x++) | ||
1249 | { | ||
1250 | SendLayerData(x, y, map); | ||
1251 | } | ||
1252 | } | ||
1253 | } | 1255 | } |
1254 | catch (Exception e) | 1256 | catch (Exception e) |
1255 | { | 1257 | { |
@@ -1257,6 +1259,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1257 | } | 1259 | } |
1258 | } | 1260 | } |
1259 | 1261 | ||
1262 | private void SendLayerTopRight(TerrainData map, int x1, int y1, int x2, int y2) | ||
1263 | { | ||
1264 | // Row | ||
1265 | for (int i = x1; i <= x2; i++) | ||
1266 | SendLayerData(i, y1, map); | ||
1267 | |||
1268 | // Column | ||
1269 | for (int j = y1 + 1; j <= y2; j++) | ||
1270 | SendLayerData(x2, j, map); | ||
1271 | |||
1272 | if (x2 - x1 > 0 && y2 - y1 > 0) | ||
1273 | SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2); | ||
1274 | } | ||
1275 | |||
1276 | void SendLayerBottomLeft(TerrainData map, int x1, int y1, int x2, int y2) | ||
1277 | { | ||
1278 | // Row in reverse | ||
1279 | for (int i = x2; i >= x1; i--) | ||
1280 | SendLayerData(i, y2, map); | ||
1281 | |||
1282 | // Column in reverse | ||
1283 | for (int j = y2 - 1; j >= y1; j--) | ||
1284 | SendLayerData(x1, j, map); | ||
1285 | |||
1286 | if (x2 - x1 > 0 && y2 - y1 > 0) | ||
1287 | SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); | ||
1288 | } | ||
1289 | |||
1290 | |||
1260 | // Legacy form of invocation that passes around a bare data array. | 1291 | // Legacy form of invocation that passes around a bare data array. |
1261 | // Just ignore what was passed and use the real terrain info that is part of the scene. | 1292 | // Just ignore what was passed and use the real terrain info that is part of the scene. |
1262 | // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI, | 1293 | // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI, |
@@ -1359,7 +1390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1359 | 1390 | ||
1360 | private void SendTheLayerPacket(LayerDataPacket layerpack) | 1391 | private void SendTheLayerPacket(LayerDataPacket layerpack) |
1361 | { | 1392 | { |
1362 | OutPacket(layerpack, ThrottleOutPacketType.Land); | 1393 | OutPacket(layerpack, ThrottleOutPacketType.Land); |
1363 | } | 1394 | } |
1364 | 1395 | ||
1365 | /// <summary> | 1396 | /// <summary> |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index e3a0825..2f4618d 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -107,6 +107,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
107 | private bool[,] updated; // for each patch, whether it needs to be sent to this client | 107 | private bool[,] updated; // for each patch, whether it needs to be sent to this client |
108 | private int updateCount; // number of patches that need to be sent | 108 | private int updateCount; // number of patches that need to be sent |
109 | public ScenePresence Presence; // a reference to the client to send to | 109 | public ScenePresence Presence; // a reference to the client to send to |
110 | public bool sendAll; | ||
111 | public int sendAllcurrentX; | ||
112 | public int sendAllcurrentY; | ||
113 | |||
110 | 114 | ||
111 | public PatchUpdates(TerrainData terrData, ScenePresence pPresence) | 115 | public PatchUpdates(TerrainData terrData, ScenePresence pPresence) |
112 | { | 116 | { |
@@ -150,6 +154,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
150 | updated[xx, yy] = state; | 154 | updated[xx, yy] = state; |
151 | if (state) | 155 | if (state) |
152 | updateCount = updated.GetLength(0) * updated.GetLength(1); | 156 | updateCount = updated.GetLength(0) * updated.GetLength(1); |
157 | sendAllcurrentX = 0; | ||
158 | sendAllcurrentY = 0; | ||
159 | sendAll = true; | ||
153 | } | 160 | } |
154 | 161 | ||
155 | // Logically OR's the terrain data's patch taint map into this client's update map. | 162 | // Logically OR's the terrain data's patch taint map into this client's update map. |
@@ -211,7 +218,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
211 | if (terrainConfig != null) | 218 | if (terrainConfig != null) |
212 | { | 219 | { |
213 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); | 220 | m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); |
214 | m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance); | 221 | m_sendTerrainUpdatesByViewDistance = |
222 | terrainConfig.GetBoolean( | ||
223 | "SendTerrainUpdatesByViewDistance",m_sendTerrainUpdatesByViewDistance); | ||
215 | } | 224 | } |
216 | } | 225 | } |
217 | 226 | ||
@@ -524,21 +533,29 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
524 | // ITerrainModule.PushTerrain() | 533 | // ITerrainModule.PushTerrain() |
525 | public void PushTerrain(IClientAPI pClient) | 534 | public void PushTerrain(IClientAPI pClient) |
526 | { | 535 | { |
527 | ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); | 536 | if (m_sendTerrainUpdatesByViewDistance) |
528 | if (presence != null) | ||
529 | { | 537 | { |
530 | lock (m_perClientPatchUpdates) | 538 | ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); |
539 | if (presence != null) | ||
531 | { | 540 | { |
532 | PatchUpdates pups; | 541 | lock (m_perClientPatchUpdates) |
533 | if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) | ||
534 | { | 542 | { |
535 | // There is a ScenePresence without a send patch map. Create one. | 543 | PatchUpdates pups; |
536 | pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence); | 544 | if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) |
537 | m_perClientPatchUpdates.Add(presence.UUID, pups); | 545 | { |
546 | // There is a ScenePresence without a send patch map. Create one. | ||
547 | pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence); | ||
548 | m_perClientPatchUpdates.Add(presence.UUID, pups); | ||
549 | } | ||
550 | pups.SetAll(true); | ||
538 | } | 551 | } |
539 | pups.SetAll(true); | ||
540 | } | 552 | } |
541 | } | 553 | } |
554 | else | ||
555 | { | ||
556 | // The traditional way is to call into the protocol stack to send them all. | ||
557 | pClient.SendLayerData(new float[10]); | ||
558 | } | ||
542 | } | 559 | } |
543 | 560 | ||
544 | #region Plugin Loading Methods | 561 | #region Plugin Loading Methods |
@@ -949,19 +966,37 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
949 | /// <param name="y">The patch corner to send</param> | 966 | /// <param name="y">The patch corner to send</param> |
950 | private void SendToClients(TerrainData terrData, int x, int y) | 967 | private void SendToClients(TerrainData terrData, int x, int y) |
951 | { | 968 | { |
952 | // Add that this patch needs to be sent to the accounting for each client. | 969 | if (m_sendTerrainUpdatesByViewDistance) |
953 | lock (m_perClientPatchUpdates) | ||
954 | { | 970 | { |
955 | m_scene.ForEachScenePresence(presence => | 971 | // Add that this patch needs to be sent to the accounting for each client. |
956 | { | 972 | lock (m_perClientPatchUpdates) |
957 | PatchUpdates thisClientUpdates; | 973 | { |
958 | if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) | 974 | m_scene.ForEachScenePresence(presence => |
959 | { | 975 | { |
960 | // There is a ScenePresence without a send patch map. Create one. | 976 | PatchUpdates thisClientUpdates; |
961 | thisClientUpdates = new PatchUpdates(terrData, presence); | 977 | if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) |
962 | m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); | 978 | { |
979 | // There is a ScenePresence without a send patch map. Create one. | ||
980 | thisClientUpdates = new PatchUpdates(terrData, presence); | ||
981 | m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); | ||
982 | } | ||
983 | thisClientUpdates.SetByXY(x, y, true); | ||
963 | } | 984 | } |
964 | thisClientUpdates.SetByXY(x, y, true); | 985 | ); |
986 | } | ||
987 | } | ||
988 | else | ||
989 | { | ||
990 | // Legacy update sending where the update is sent out as soon as noticed | ||
991 | // We know the actual terrain data that is passed is ignored so this passes a dummy heightmap. | ||
992 | //float[] heightMap = terrData.GetFloatsSerialized(); | ||
993 | float[] heightMap = new float[10]; | ||
994 | m_scene.ForEachClient( | ||
995 | delegate (IClientAPI controller) | ||
996 | { | ||
997 | controller.SendLayerData(x / Constants.TerrainPatchSize, | ||
998 | y / Constants.TerrainPatchSize, | ||
999 | heightMap); | ||
965 | } | 1000 | } |
966 | ); | 1001 | ); |
967 | } | 1002 | } |
@@ -993,46 +1028,113 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
993 | { | 1028 | { |
994 | foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) | 1029 | foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) |
995 | { | 1030 | { |
996 | if (!Monitor.TryEnter(pups)) | ||
997 | continue; | ||
998 | |||
999 | // throught acording to land queue free to send bytes | 1031 | // throught acording to land queue free to send bytes |
1000 | if (!pups.Presence.ControllingClient.CanSendLayerData()) | 1032 | if (!pups.Presence.ControllingClient.CanSendLayerData()) |
1001 | continue; | 1033 | continue; |
1002 | 1034 | ||
1003 | if (pups.HasUpdates()) | 1035 | if (pups.HasUpdates()) |
1004 | { | 1036 | { |
1005 | 1037 | if (m_sendTerrainUpdatesByViewDistance) | |
1006 | // There is something that could be sent to this client. | ||
1007 | List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups); | ||
1008 | if (toSend.Count > 0) | ||
1009 | { | 1038 | { |
1010 | // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", | 1039 | // There is something that could be sent to this client. |
1011 | // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); | 1040 | List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups); |
1012 | // Sort the patches to send by the distance from the presence | 1041 | if (toSend.Count > 0) |
1013 | toSend.Sort(); | ||
1014 | /* | ||
1015 | foreach (PatchesToSend pts in toSend) | ||
1016 | { | 1042 | { |
1017 | pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); | 1043 | // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", |
1018 | // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); | 1044 | // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); |
1045 | // Sort the patches to send by the distance from the presence | ||
1046 | toSend.Sort(); | ||
1047 | /* | ||
1048 | foreach (PatchesToSend pts in toSend) | ||
1049 | { | ||
1050 | pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); | ||
1051 | // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); | ||
1052 | } | ||
1053 | */ | ||
1054 | |||
1055 | int[] xPieces = new int[toSend.Count]; | ||
1056 | int[] yPieces = new int[toSend.Count]; | ||
1057 | float[] patchPieces = new float[toSend.Count * 2]; | ||
1058 | int pieceIndex = 0; | ||
1059 | foreach (PatchesToSend pts in toSend) | ||
1060 | { | ||
1061 | patchPieces[pieceIndex++] = pts.PatchX; | ||
1062 | patchPieces[pieceIndex++] = pts.PatchY; | ||
1063 | } | ||
1064 | pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); | ||
1019 | } | 1065 | } |
1020 | */ | 1066 | if (pups.sendAll && toSend.Count < 1024) |
1067 | SendAllModifiedPatchs(pups); | ||
1068 | } | ||
1069 | else | ||
1070 | SendAllModifiedPatchs(pups); | ||
1071 | } | ||
1072 | } | ||
1073 | } | ||
1074 | } | ||
1075 | private void SendAllModifiedPatchs(PatchUpdates pups) | ||
1076 | { | ||
1077 | if (!pups.sendAll) // sanity | ||
1078 | return; | ||
1021 | 1079 | ||
1022 | int[] xPieces = new int[toSend.Count]; | 1080 | int limitX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize; |
1023 | int[] yPieces = new int[toSend.Count]; | 1081 | int limitY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize; |
1024 | float[] patchPieces = new float[toSend.Count * 2]; | 1082 | |
1025 | int pieceIndex = 0; | 1083 | if (pups.sendAllcurrentX > limitX || pups.sendAllcurrentY > limitY) |
1026 | foreach (PatchesToSend pts in toSend) | 1084 | { |
1027 | { | 1085 | pups.sendAll = false; |
1028 | patchPieces[pieceIndex++] = pts.PatchX; | 1086 | pups.sendAllcurrentX = 0; |
1029 | patchPieces[pieceIndex++] = pts.PatchY; | 1087 | pups.sendAllcurrentY = 0; |
1030 | } | 1088 | return; |
1031 | pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); | 1089 | } |
1090 | |||
1091 | int npatchs = 0; | ||
1092 | List<PatchesToSend> patchs = new List<PatchesToSend>(); | ||
1093 | int x = pups.sendAllcurrentX; | ||
1094 | int y = pups.sendAllcurrentY; | ||
1095 | // send it in the order viewer draws it | ||
1096 | // even if not best for memory scan | ||
1097 | for (; y < limitY; y++) | ||
1098 | { | ||
1099 | for (; x < limitX; x++) | ||
1100 | { | ||
1101 | if (pups.GetByPatch(x, y)) | ||
1102 | { | ||
1103 | pups.SetByPatch(x, y, false); | ||
1104 | patchs.Add(new PatchesToSend(x, y, 0)); | ||
1105 | if (++npatchs >= 512) | ||
1106 | { | ||
1107 | pups.sendAllcurrentX = x + 1; | ||
1108 | pups.sendAllcurrentY = y; | ||
1109 | break; | ||
1032 | } | 1110 | } |
1033 | } | 1111 | } |
1034 | Monitor.Exit(pups); | ||
1035 | } | 1112 | } |
1113 | if (npatchs >= 512) | ||
1114 | break; | ||
1115 | x = 0; | ||
1116 | } | ||
1117 | |||
1118 | if (x >= limitX && y >= limitY) | ||
1119 | { | ||
1120 | pups.sendAll = false; | ||
1121 | pups.sendAllcurrentX = 0; | ||
1122 | pups.sendAllcurrentY = 0; | ||
1123 | } | ||
1124 | |||
1125 | npatchs = patchs.Count; | ||
1126 | if (npatchs > 0) | ||
1127 | { | ||
1128 | int[] xPieces = new int[npatchs]; | ||
1129 | int[] yPieces = new int[npatchs]; | ||
1130 | float[] patchPieces = new float[npatchs * 2]; | ||
1131 | int pieceIndex = 0; | ||
1132 | foreach (PatchesToSend pts in patchs) | ||
1133 | { | ||
1134 | patchPieces[pieceIndex++] = pts.PatchX; | ||
1135 | patchPieces[pieceIndex++] = pts.PatchY; | ||
1136 | } | ||
1137 | pups.Presence.ControllingClient.SendLayerData(-npatchs, 0, patchPieces); | ||
1036 | } | 1138 | } |
1037 | } | 1139 | } |
1038 | 1140 | ||
@@ -1119,7 +1221,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1119 | { | 1221 | { |
1120 | pups.SetByPatch(x, y, false); | 1222 | pups.SetByPatch(x, y, false); |
1121 | ret.Add(new PatchesToSend(x, y, (float)distsq)); | 1223 | ret.Add(new PatchesToSend(x, y, (float)distsq)); |
1122 | if (npatchs++ > 65536) | 1224 | if (npatchs++ > 1024) |
1123 | { | 1225 | { |
1124 | y = endY; | 1226 | y = endY; |
1125 | x = endX; | 1227 | x = endX; |