diff options
author | Melanie | 2012-07-08 10:44:53 +0200 |
---|---|---|
committer | Melanie | 2012-07-08 10:44:53 +0200 |
commit | 1e4c65649736db82d0221b6b2aa57f7f45c7163c (patch) | |
tree | 064b128509b7a91ebebbf94d094c1a25be16a9da /OpenSim/Region/CoreModules | |
parent | Instead of sending 20 records in 2 packets, send just one as we intended in t... (diff) | |
download | opensim-SC_OLD-1e4c65649736db82d0221b6b2aa57f7f45c7163c.zip opensim-SC_OLD-1e4c65649736db82d0221b6b2aa57f7f45c7163c.tar.gz opensim-SC_OLD-1e4c65649736db82d0221b6b2aa57f7f45c7163c.tar.bz2 opensim-SC_OLD-1e4c65649736db82d0221b6b2aa57f7f45c7163c.tar.xz |
Revamp map block sending to eliminate overload of the grid server connection
and the sim's http client
Diffstat (limited to 'OpenSim/Region/CoreModules')
-rw-r--r-- | OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | 4 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | 298 |
2 files changed, 204 insertions, 98 deletions
diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index 0c60391..4f18b53 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | |||
@@ -90,9 +90,9 @@ namespace OpenSim.Region.CoreModules.Hypergrid | |||
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 | ||
93 | protected override List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) | 93 | protected override List<MapBlockData> GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) |
94 | { | 94 | { |
95 | List<MapBlockData> mapBlocks = base.GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); | 95 | List<MapBlockData> mapBlocks = base.GetAndSendBlocksInternal(remoteClient, minX, minY, maxX, maxY, flag); |
96 | lock (m_SeenMapBlocks) | 96 | lock (m_SeenMapBlocks) |
97 | { | 97 | { |
98 | if (!m_SeenMapBlocks.ContainsKey(remoteClient.AgentId)) | 98 | if (!m_SeenMapBlocks.ContainsKey(remoteClient.AgentId)) |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 88aacb9..a226b78 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | |||
@@ -66,6 +66,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
66 | private ManualResetEvent queueEvent = new ManualResetEvent(false); | 66 | private ManualResetEvent queueEvent = new ManualResetEvent(false); |
67 | private Queue<MapRequestState> requests = new Queue<MapRequestState>(); | 67 | private Queue<MapRequestState> requests = new Queue<MapRequestState>(); |
68 | 68 | ||
69 | private ManualResetEvent m_mapBlockRequestEvent = new ManualResetEvent(false); | ||
70 | private Dictionary<UUID, Queue<MapBlockRequestData>> m_mapBlockRequests = new Dictionary<UUID, Queue<MapBlockRequestData>>(); | ||
71 | |||
69 | protected Scene m_scene; | 72 | protected Scene m_scene; |
70 | private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>(); | 73 | private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>(); |
71 | private int cachedTime = 0; | 74 | private int cachedTime = 0; |
@@ -227,54 +230,54 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
227 | // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is | 230 | // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is |
228 | // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks. | 231 | // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks. |
229 | 232 | ||
230 | if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) | 233 | //if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) |
231 | { | 234 | //{ |
232 | ScenePresence avatarPresence = null; | 235 | // ScenePresence avatarPresence = null; |
233 | 236 | ||
234 | m_scene.TryGetScenePresence(agentID, out avatarPresence); | 237 | // m_scene.TryGetScenePresence(agentID, out avatarPresence); |
235 | 238 | ||
236 | if (avatarPresence != null) | 239 | // if (avatarPresence != null) |
237 | { | 240 | // { |
238 | bool lookup = false; | 241 | // bool lookup = false; |
239 | 242 | ||
240 | lock (cachedMapBlocks) | 243 | // lock (cachedMapBlocks) |
241 | { | 244 | // { |
242 | if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) | 245 | // if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) |
243 | { | 246 | // { |
244 | List<MapBlockData> mapBlocks; | 247 | // List<MapBlockData> mapBlocks; |
245 | 248 | ||
246 | mapBlocks = cachedMapBlocks; | 249 | // mapBlocks = cachedMapBlocks; |
247 | avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); | 250 | // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); |
248 | } | 251 | // } |
249 | else | 252 | // else |
250 | { | 253 | // { |
251 | lookup = true; | 254 | // lookup = true; |
252 | } | 255 | // } |
253 | } | 256 | // } |
254 | if (lookup) | 257 | // if (lookup) |
255 | { | 258 | // { |
256 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; | 259 | // List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; |
257 | 260 | ||
258 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 261 | // List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
259 | (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, | 262 | // (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, |
260 | (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, | 263 | // (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, |
261 | (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, | 264 | // (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, |
262 | (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); | 265 | // (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); |
263 | foreach (GridRegion r in regions) | 266 | // foreach (GridRegion r in regions) |
264 | { | 267 | // { |
265 | MapBlockData block = new MapBlockData(); | 268 | // MapBlockData block = new MapBlockData(); |
266 | MapBlockFromGridRegion(block, r, 0); | 269 | // MapBlockFromGridRegion(block, r, 0); |
267 | mapBlocks.Add(block); | 270 | // mapBlocks.Add(block); |
268 | } | 271 | // } |
269 | avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); | 272 | // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); |
270 | 273 | ||
271 | lock (cachedMapBlocks) | 274 | // lock (cachedMapBlocks) |
272 | cachedMapBlocks = mapBlocks; | 275 | // cachedMapBlocks = mapBlocks; |
273 | 276 | ||
274 | cachedTime = Util.UnixTimeSinceEpoch(); | 277 | // cachedTime = Util.UnixTimeSinceEpoch(); |
275 | } | 278 | // } |
276 | } | 279 | // } |
277 | } | 280 | //} |
278 | 281 | ||
279 | LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); | 282 | LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); |
280 | mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); | 283 | mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); |
@@ -301,8 +304,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
301 | protected static OSDMapLayer GetOSDMapLayerResponse() | 304 | protected static OSDMapLayer GetOSDMapLayerResponse() |
302 | { | 305 | { |
303 | OSDMapLayer mapLayer = new OSDMapLayer(); | 306 | OSDMapLayer mapLayer = new OSDMapLayer(); |
304 | mapLayer.Right = 5000; | 307 | mapLayer.Right = 2048; |
305 | mapLayer.Top = 5000; | 308 | mapLayer.Top = 2048; |
306 | mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); | 309 | mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); |
307 | 310 | ||
308 | return mapLayer; | 311 | return mapLayer; |
@@ -331,6 +334,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
331 | { | 334 | { |
332 | m_rootAgents.Remove(AgentId); | 335 | m_rootAgents.Remove(AgentId); |
333 | } | 336 | } |
337 | lock (m_mapBlockRequestEvent) | ||
338 | { | ||
339 | if (m_mapBlockRequests.ContainsKey(AgentId)) | ||
340 | m_mapBlockRequests.Remove(AgentId); | ||
341 | } | ||
334 | } | 342 | } |
335 | #endregion | 343 | #endregion |
336 | 344 | ||
@@ -353,6 +361,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
353 | ThreadPriority.BelowNormal, | 361 | ThreadPriority.BelowNormal, |
354 | true, | 362 | true, |
355 | true); | 363 | true); |
364 | Watchdog.StartThread( | ||
365 | MapBlockSendThread, | ||
366 | string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName), | ||
367 | ThreadPriority.BelowNormal, | ||
368 | true, | ||
369 | true); | ||
356 | } | 370 | } |
357 | 371 | ||
358 | /// <summary> | 372 | /// <summary> |
@@ -373,6 +387,22 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
373 | queueEvent.Set(); | 387 | queueEvent.Set(); |
374 | requests.Enqueue(st); | 388 | requests.Enqueue(st); |
375 | } | 389 | } |
390 | |||
391 | MapBlockRequestData req = new MapBlockRequestData(); | ||
392 | |||
393 | req.client = null; | ||
394 | req.minX = 0; | ||
395 | req.maxX = 0; | ||
396 | req.minY = 0; | ||
397 | req.maxY = 0; | ||
398 | req.flags = 0; | ||
399 | |||
400 | lock (m_mapBlockRequestEvent) | ||
401 | { | ||
402 | m_mapBlockRequests[UUID.Zero] = new Queue<MapBlockRequestData>(); | ||
403 | m_mapBlockRequests[UUID.Zero].Enqueue(req); | ||
404 | m_mapBlockRequestEvent.Set(); | ||
405 | } | ||
376 | } | 406 | } |
377 | 407 | ||
378 | public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, | 408 | public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, |
@@ -932,84 +962,144 @@ return; | |||
932 | /// <param name="minY"></param> | 962 | /// <param name="minY"></param> |
933 | /// <param name="maxX"></param> | 963 | /// <param name="maxX"></param> |
934 | /// <param name="maxY"></param> | 964 | /// <param name="maxY"></param> |
935 | public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) | 965 | public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) |
936 | { | 966 | { |
937 | Util.FireAndForget(x => | 967 | //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); |
968 | if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible | ||
938 | { | 969 | { |
939 | //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); | 970 | List<MapBlockData> response = new List<MapBlockData>(); |
940 | if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible | 971 | |
972 | // this should return one mapblock at most. It is triggered by a click | ||
973 | // on an unloaded square. | ||
974 | // But make sure: Look whether the one we requested is in there | ||
975 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | ||
976 | minX * (int)Constants.RegionSize, | ||
977 | maxX * (int)Constants.RegionSize, | ||
978 | minY * (int)Constants.RegionSize, | ||
979 | maxY * (int)Constants.RegionSize); | ||
980 | |||
981 | if (regions != null) | ||
941 | { | 982 | { |
942 | List<MapBlockData> response = new List<MapBlockData>(); | 983 | foreach (GridRegion r in regions) |
943 | |||
944 | // this should return one mapblock at most. It is triggered by a click | ||
945 | // on an unloaded square. | ||
946 | // But make sure: Look whether the one we requested is in there | ||
947 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | ||
948 | minX * (int)Constants.RegionSize, | ||
949 | maxX * (int)Constants.RegionSize, | ||
950 | minY * (int)Constants.RegionSize, | ||
951 | maxY * (int)Constants.RegionSize); | ||
952 | |||
953 | if (regions != null) | ||
954 | { | 984 | { |
955 | foreach (GridRegion r in regions) | 985 | if ((r.RegionLocX == minX * (int)Constants.RegionSize) && |
986 | (r.RegionLocY == minY * (int)Constants.RegionSize)) | ||
956 | { | 987 | { |
957 | if ((r.RegionLocX == minX * (int)Constants.RegionSize) && | 988 | // found it => add it to response |
958 | (r.RegionLocY == minY * (int)Constants.RegionSize)) | 989 | MapBlockData block = new MapBlockData(); |
959 | { | 990 | MapBlockFromGridRegion(block, r, flag); |
960 | // found it => add it to response | 991 | response.Add(block); |
961 | MapBlockData block = new MapBlockData(); | 992 | break; |
962 | MapBlockFromGridRegion(block, r, flag); | ||
963 | response.Add(block); | ||
964 | break; | ||
965 | } | ||
966 | } | 993 | } |
967 | } | 994 | } |
995 | } | ||
968 | 996 | ||
969 | if (response.Count == 0) | 997 | if (response.Count == 0) |
998 | { | ||
999 | // response still empty => couldn't find the map-tile the user clicked on => tell the client | ||
1000 | MapBlockData block = new MapBlockData(); | ||
1001 | block.X = (ushort)minX; | ||
1002 | block.Y = (ushort)minY; | ||
1003 | block.Access = 254; // means 'simulator is offline' | ||
1004 | response.Add(block); | ||
1005 | } | ||
1006 | // The lower 16 bits are an unsigned int16 | ||
1007 | remoteClient.SendMapBlock(response, flag & 0xffff); | ||
1008 | } | ||
1009 | else | ||
1010 | { | ||
1011 | // normal mapblock request. Use the provided values | ||
1012 | GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) | ||
1017 | { | ||
1018 | MapBlockRequestData req = new MapBlockRequestData(); | ||
1019 | |||
1020 | req.client = remoteClient; | ||
1021 | req.minX = minX; | ||
1022 | req.maxX = maxX; | ||
1023 | req.minY = minY; | ||
1024 | req.maxY = maxY; | ||
1025 | req.flags = flag; | ||
1026 | |||
1027 | lock (m_mapBlockRequestEvent) | ||
1028 | { | ||
1029 | if (!m_mapBlockRequests.ContainsKey(remoteClient.AgentId)) | ||
1030 | m_mapBlockRequests[remoteClient.AgentId] = new Queue<MapBlockRequestData>(); | ||
1031 | m_mapBlockRequests[remoteClient.AgentId].Enqueue(req); | ||
1032 | m_mapBlockRequestEvent.Set(); | ||
1033 | } | ||
1034 | |||
1035 | return new List<MapBlockData>(); | ||
1036 | } | ||
1037 | |||
1038 | protected void MapBlockSendThread() | ||
1039 | { | ||
1040 | while (true) | ||
1041 | { | ||
1042 | List<MapBlockRequestData> thisRunData = new List<MapBlockRequestData>(); | ||
1043 | |||
1044 | m_mapBlockRequestEvent.WaitOne(); | ||
1045 | lock (m_mapBlockRequestEvent) | ||
1046 | { | ||
1047 | int total = 0; | ||
1048 | foreach (Queue<MapBlockRequestData> q in m_mapBlockRequests.Values) | ||
970 | { | 1049 | { |
971 | // response still empty => couldn't find the map-tile the user clicked on => tell the client | 1050 | if (q.Count > 0) |
972 | MapBlockData block = new MapBlockData(); | 1051 | thisRunData.Add(q.Dequeue()); |
973 | block.X = (ushort)minX; | 1052 | |
974 | block.Y = (ushort)minY; | 1053 | total += q.Count; |
975 | block.Access = 254; // means 'simulator is offline' | ||
976 | response.Add(block); | ||
977 | } | 1054 | } |
978 | // The lower 16 bits are an unsigned int16 | 1055 | |
979 | remoteClient.SendMapBlock(response, flag & 0xffff); | 1056 | if (total == 0) |
1057 | m_mapBlockRequestEvent.Reset(); | ||
980 | } | 1058 | } |
981 | else | 1059 | |
1060 | foreach (MapBlockRequestData req in thisRunData) | ||
982 | { | 1061 | { |
983 | // normal mapblock request. Use the provided values | 1062 | // Null client stops thread |
984 | GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); | 1063 | if (req.client == null) |
1064 | return; | ||
1065 | |||
1066 | GetAndSendBlocksInternal(req.client, req.minX, req.minY, req.maxX, req.maxY, req.flags); | ||
985 | } | 1067 | } |
986 | }); | 1068 | |
1069 | Thread.Sleep(50); | ||
1070 | } | ||
987 | } | 1071 | } |
988 | 1072 | ||
989 | protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) | 1073 | protected virtual List<MapBlockData> GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) |
990 | { | 1074 | { |
1075 | List<MapBlockData> allBlocks = new List<MapBlockData>(); | ||
991 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); | 1076 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); |
992 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 1077 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
993 | (minX - 4) * (int)Constants.RegionSize, | 1078 | minX * (int)Constants.RegionSize, |
994 | (maxX + 4) * (int)Constants.RegionSize, | 1079 | maxX * (int)Constants.RegionSize, |
995 | (minY - 4) * (int)Constants.RegionSize, | 1080 | minY * (int)Constants.RegionSize, |
996 | (maxY + 4) * (int)Constants.RegionSize); | 1081 | maxY * (int)Constants.RegionSize); |
1082 | // (minX - 4) * (int)Constants.RegionSize, | ||
1083 | // (maxX + 4) * (int)Constants.RegionSize, | ||
1084 | // (minY - 4) * (int)Constants.RegionSize, | ||
1085 | // (maxY + 4) * (int)Constants.RegionSize); | ||
997 | foreach (GridRegion r in regions) | 1086 | foreach (GridRegion r in regions) |
998 | { | 1087 | { |
999 | MapBlockData block = new MapBlockData(); | 1088 | MapBlockData block = new MapBlockData(); |
1000 | MapBlockFromGridRegion(block, r, flag); | 1089 | MapBlockFromGridRegion(block, r, flag); |
1001 | mapBlocks.Add(block); | 1090 | mapBlocks.Add(block); |
1091 | allBlocks.Add(block); | ||
1002 | if (mapBlocks.Count >= 10) | 1092 | if (mapBlocks.Count >= 10) |
1003 | { | 1093 | { |
1004 | remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); | 1094 | remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); |
1005 | mapBlocks.Clear(); | 1095 | mapBlocks.Clear(); |
1006 | Thread.Sleep(1000); | 1096 | Thread.Sleep(50); |
1007 | } | 1097 | } |
1008 | } | 1098 | } |
1009 | if (mapBlocks.Count > 0) | 1099 | if (mapBlocks.Count > 0) |
1010 | remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); | 1100 | remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); |
1011 | 1101 | ||
1012 | return mapBlocks; | 1102 | return allBlocks; |
1013 | } | 1103 | } |
1014 | 1104 | ||
1015 | protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) | 1105 | protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) |
@@ -1408,6 +1498,12 @@ return; | |||
1408 | { | 1498 | { |
1409 | m_rootAgents.Remove(avatar.UUID); | 1499 | m_rootAgents.Remove(avatar.UUID); |
1410 | } | 1500 | } |
1501 | |||
1502 | lock (m_mapBlockRequestEvent) | ||
1503 | { | ||
1504 | if (m_mapBlockRequests.ContainsKey(avatar.UUID)) | ||
1505 | m_mapBlockRequests.Remove(avatar.UUID); | ||
1506 | } | ||
1411 | } | 1507 | } |
1412 | 1508 | ||
1413 | public void OnRegionUp(GridRegion otherRegion) | 1509 | public void OnRegionUp(GridRegion otherRegion) |
@@ -1531,4 +1627,14 @@ return; | |||
1531 | public uint itemtype; | 1627 | public uint itemtype; |
1532 | public ulong regionhandle; | 1628 | public ulong regionhandle; |
1533 | } | 1629 | } |
1630 | |||
1631 | public struct MapBlockRequestData | ||
1632 | { | ||
1633 | public IClientAPI client; | ||
1634 | public int minX; | ||
1635 | public int minY; | ||
1636 | public int maxX; | ||
1637 | public int maxY; | ||
1638 | public uint flags; | ||
1639 | } | ||
1534 | } | 1640 | } |