aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/WorldMap
diff options
context:
space:
mode:
authoronefang2019-05-19 21:24:15 +1000
committeronefang2019-05-19 21:24:15 +1000
commit5e4d6cab00cb29cd088ab7b62ab13aff103b64cb (patch)
treea9fbc62df9eb2d1d9ba2698d8552eae71eca20d8 /OpenSim/Region/CoreModules/World/WorldMap
parentAdd a build script. (diff)
downloadopensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.zip
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.gz
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.bz2
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.xz
Dump OpenSim 0.9.0.1 into it's own branch.
Diffstat (limited to 'OpenSim/Region/CoreModules/World/WorldMap')
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs167
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs1579
2 files changed, 970 insertions, 776 deletions
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
index d862f18..5876df3 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -128,109 +128,116 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
128 m_Clients.Add(remoteClient.AgentId); 128 m_Clients.Add(remoteClient.AgentId);
129 } 129 }
130 130
131 try 131 OnMapNameRequest(remoteClient, mapName, flags);
132 {
133 OnMapNameRequest(remoteClient, mapName, flags);
134 }
135 finally
136 {
137 lock (m_Clients)
138 m_Clients.Remove(remoteClient.AgentId);
139 }
140 } 132 }
141 133
142 private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) 134 private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags)
143 { 135 {
144 List<MapBlockData> blocks = new List<MapBlockData>(); 136 Util.FireAndForget(x =>
145 if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4))
146 { 137 {
147 // final block, closing the search result 138 try
148 AddFinalBlock(blocks); 139 {
140 List<MapBlockData> blocks = new List<MapBlockData>();
141 if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4))
142 {
143 // final block, closing the search result
144 AddFinalBlock(blocks,mapName);
149 145
150 // flags are agent flags sent from the viewer. 146 // flags are agent flags sent from the viewer.
151 // they have different values depending on different viewers, apparently 147 // they have different values depending on different viewers, apparently
152 remoteClient.SendMapBlock(blocks, flags); 148 remoteClient.SendMapBlock(blocks, flags);
153 remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); 149 remoteClient.SendAlertMessage("Use a search string with at least 3 characters");
154 return; 150 return;
155 } 151 }
156 152
153 //m_log.DebugFormat("MAP NAME=({0})", mapName);
157 154
158 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); 155 // Hack to get around the fact that ll V3 now drops the port from the
159 156 // map name. See https://jira.secondlife.com/browse/VWR-28570
160 string mapNameOrig = mapName; 157 //
161 if (regionInfos.Count == 0) 158 // Caller, use this magic form instead:
162 { 159 // secondlife://http|!!mygrid.com|8002|Region+Name/128/128
163 // Hack to get around the fact that ll V3 now drops the port from the 160 // or url encode if possible.
164 // map name. See https://jira.secondlife.com/browse/VWR-28570 161 // the hacks we do with this viewer...
165 // 162 //
166 // Caller, use this magic form instead: 163 bool needOriginalName = false;
167 // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 164 string mapNameOrig = mapName;
168 // or url encode if possible. 165 if (mapName.Contains("|"))
169 // the hacks we do with this viewer...
170 //
171 if (mapName.Contains("|"))
172 mapName = mapName.Replace('|', ':');
173 if (mapName.Contains("+"))
174 mapName = mapName.Replace('+', ' ');
175 if (mapName.Contains("!"))
176 mapName = mapName.Replace('!', '/');
177
178 if (mapName != mapNameOrig)
179 regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
180 }
181
182 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags);
183
184 if (regionInfos.Count > 0)
185 {
186 foreach (GridRegion info in regionInfos)
187 {
188 if ((flags & 2) == 2) // V2 sends this
189 { 166 {
190 List<MapBlockData> datas = WorldMap.Map2BlockFromGridRegion(info, flags); 167 mapName = mapName.Replace('|', ':');
191 // ugh! V2-3 is very sensitive about the result being 168 needOriginalName = true;
192 // exactly the same as the requested name
193 if (regionInfos.Count == 1 && (mapName != mapNameOrig))
194 datas.ForEach(d => d.Name = mapNameOrig);
195
196 blocks.AddRange(datas);
197 } 169 }
198 else 170 if (mapName.Contains("+"))
199 { 171 {
200 MapBlockData data = WorldMap.MapBlockFromGridRegion(info, flags); 172 mapName = mapName.Replace('+', ' ');
201 blocks.Add(data); 173 needOriginalName = true;
202 } 174 }
203 } 175 if (mapName.Contains("!"))
204 } 176 {
177 mapName = mapName.Replace('!', '/');
178 needOriginalName = true;
179 }
180 if (mapName.Contains("."))
181 needOriginalName = true;
205 182
206 // final block, closing the search result 183 // try to fetch from GridServer
207 AddFinalBlock(blocks); 184 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
185 // if (regionInfos.Count == 0)
186 // remoteClient.SendAlertMessage("Hyperlink could not be established.");
208 187
209 // flags are agent flags sent from the viewer. 188 //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count);
210 // they have different values depending on different viewers, apparently
211 remoteClient.SendMapBlock(blocks, flags);
212 189
213 // send extra user messages for V3 190 MapBlockData data;
214 // because the UI is very confusing 191 if (regionInfos != null && regionInfos.Count > 0)
215 // while we don't fix the hard-coded urls 192 {
216 if (flags == 2) 193 foreach (GridRegion info in regionInfos)
217 { 194 {
218 if (regionInfos.Count == 0) 195 data = new MapBlockData();
219 remoteClient.SendAlertMessage("No regions found with that name."); 196 data.Agents = 0;
220 // this seems unnecessary because found regions will show up in the search results 197 data.Access = info.Access;
221 //else if (regionInfos.Count == 1) 198 MapBlockData block = new MapBlockData();
222 // remoteClient.SendAlertMessage("Region found!"); 199 WorldMap.MapBlockFromGridRegion(block, info, flags);
223 } 200
201 if (flags == 2 && regionInfos.Count == 1 && needOriginalName)
202 block.Name = mapNameOrig;
203 blocks.Add(block);
204 }
205 }
206
207 // final block, closing the search result
208 AddFinalBlock(blocks,mapNameOrig);
209
210 // flags are agent flags sent from the viewer.
211 // they have different values depending on different viewers, apparently
212 remoteClient.SendMapBlock(blocks, flags);
213
214 // send extra user messages for V3
215 // because the UI is very confusing
216 // while we don't fix the hard-coded urls
217 if (flags == 2)
218 {
219 if (regionInfos == null || regionInfos.Count == 0)
220 remoteClient.SendAgentAlertMessage("No regions found with that name.", true);
221 // else if (regionInfos.Count == 1)
222 // remoteClient.SendAgentAlertMessage("Region found!", false);
223 }
224 }
225 finally
226 {
227 lock (m_Clients)
228 m_Clients.Remove(remoteClient.AgentId);
229 }
230 });
224 } 231 }
225 232
226 private void AddFinalBlock(List<MapBlockData> blocks) 233 private void AddFinalBlock(List<MapBlockData> blocks,string name)
227 { 234 {
228 // final block, closing the search result 235 // final block, closing the search result
229 MapBlockData data = new MapBlockData(); 236 MapBlockData data = new MapBlockData();
230 data.Agents = 0; 237 data.Agents = 0;
231 data.Access = (byte)SimAccess.NonExistent; 238 data.Access = (byte)SimAccess.NonExistent;
232 data.MapImageId = UUID.Zero; 239 data.MapImageId = UUID.Zero;
233 data.Name = ""; 240 data.Name = name;
234 data.RegionFlags = 0; 241 data.RegionFlags = 0;
235 data.WaterHeight = 0; // not used 242 data.WaterHeight = 0; // not used
236 data.X = 0; 243 data.X = 0;
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index db1187e..03a4d34 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -66,32 +66,34 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
66 66
67 private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg"; 67 private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg";
68 private static readonly UUID STOP_UUID = UUID.Random(); 68 private static readonly UUID STOP_UUID = UUID.Random();
69 private static readonly string m_mapLayerPath = "0001/"; 69
70 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
71
72 private ManualResetEvent m_mapBlockRequestEvent = new ManualResetEvent(false);
73 private Dictionary<UUID, Queue<MapBlockRequestData>> m_mapBlockRequests = new Dictionary<UUID, Queue<MapBlockRequestData>>();
70 74
71 private IMapImageGenerator m_mapImageGenerator; 75 private IMapImageGenerator m_mapImageGenerator;
72 private IMapImageUploadModule m_mapImageServiceModule; 76 private IMapImageUploadModule m_mapImageServiceModule;
73 77
74 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
75
76 protected Scene m_scene; 78 protected Scene m_scene;
77 private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>(); 79 private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
78 private int cachedTime = 0;
79 private int blacklistTimeout = 10*60*1000; // 10 minutes
80 private byte[] myMapImageJPEG; 80 private byte[] myMapImageJPEG;
81 protected volatile bool m_Enabled = false; 81 protected volatile bool m_Enabled = false;
82 private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>(); 82 private ExpiringCache<string, int> m_blacklistedurls = new ExpiringCache<string, int>();
83 private Dictionary<string, int> m_blacklistedurls = new Dictionary<string, int>(); 83 private ExpiringCache<ulong, int> m_blacklistedregions = new ExpiringCache<ulong, int>();
84 private Dictionary<ulong, int> m_blacklistedregions = new Dictionary<ulong, int>(); 84 private ExpiringCache<ulong, string> m_cachedRegionMapItemsAddress = new ExpiringCache<ulong, string>();
85 private Dictionary<ulong, string> m_cachedRegionMapItemsAddress = new Dictionary<ulong, string>(); 85 private ExpiringCache<ulong, OSDMap> m_cachedRegionMapItemsResponses =
86 new ExpiringCache<ulong, OSDMap>();
86 private List<UUID> m_rootAgents = new List<UUID>(); 87 private List<UUID> m_rootAgents = new List<UUID>();
87 private volatile bool threadrunning = false; 88 private volatile bool threadrunning = false;
88 89 // expire time for the blacklists in seconds
89 private IServiceThrottleModule m_ServiceThrottle; 90 private double expireBlackListTime = 600.0; // 10 minutes
90 91 // expire mapItems responses time in seconds. Throttles requests to regions that do answer
92 private const double expireResponsesTime = 120.0; // 2 minutes ?
91 //private int CacheRegionsDistance = 256; 93 //private int CacheRegionsDistance = 256;
92 94
93 #region INonSharedRegionModule Members 95 #region INonSharedRegionModule Members
94 public virtual void Initialise (IConfigSource config) 96 public virtual void Initialise(IConfigSource config)
95 { 97 {
96 string[] configSections = new string[] { "Map", "Startup" }; 98 string[] configSections = new string[] { "Map", "Startup" };
97 99
@@ -99,8 +101,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
99 config, "WorldMapModule", configSections, "WorldMap") == "WorldMap") 101 config, "WorldMapModule", configSections, "WorldMap") == "WorldMap")
100 m_Enabled = true; 102 m_Enabled = true;
101 103
102 blacklistTimeout 104 expireBlackListTime = (double)Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60);
103 = Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000;
104 } 105 }
105 106
106 public virtual void AddRegion(Scene scene) 107 public virtual void AddRegion(Scene scene)
@@ -128,7 +129,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
128 } 129 }
129 } 130 }
130 131
131 public virtual void RemoveRegion (Scene scene) 132 public virtual void RemoveRegion(Scene scene)
132 { 133 {
133 if (!m_Enabled) 134 if (!m_Enabled)
134 return; 135 return;
@@ -141,13 +142,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
141 } 142 }
142 } 143 }
143 144
144 public virtual void RegionLoaded (Scene scene) 145 public virtual void RegionLoaded(Scene scene)
145 { 146 {
146 if (!m_Enabled) 147 if (!m_Enabled)
147 return; 148 return;
148 149
149 m_ServiceThrottle = scene.RequestModuleInterface<IServiceThrottleModule>();
150
151 m_mapImageGenerator = m_scene.RequestModuleInterface<IMapImageGenerator>(); 150 m_mapImageGenerator = m_scene.RequestModuleInterface<IMapImageGenerator>();
152 m_mapImageServiceModule = m_scene.RequestModuleInterface<IMapImageUploadModule>(); 151 m_mapImageServiceModule = m_scene.RequestModuleInterface<IMapImageUploadModule>();
153 } 152 }
@@ -177,16 +176,20 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
177 regionimage = regionimage.Replace("-", ""); 176 regionimage = regionimage.Replace("-", "");
178 m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage); 177 m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage);
179 178
179/*
180 MainServer.Instance.AddHTTPHandler(regionimage, 180 MainServer.Instance.AddHTTPHandler(regionimage,
181 new GenericHTTPDOSProtector(OnHTTPGetMapImage, OnHTTPThrottled, new BasicDosProtectorOptions() 181 new GenericHTTPDOSProtector(OnHTTPGetMapImage, OnHTTPThrottled, new BasicDosProtectorOptions()
182 { 182 {
183 AllowXForwardedFor = false, 183 AllowXForwardedFor = false,
184 ForgetTimeSpan = TimeSpan.FromMinutes(2), 184 ForgetTimeSpan = TimeSpan.FromMinutes(2),
185 MaxRequestsInTimeframe = 4, 185 MaxRequestsInTimeframe = 4,
186 ReportingName = "MAPDOSPROTECTOR", 186 ReportingName = "MAPDOSPROTECTOR",
187 RequestTimeSpan = TimeSpan.FromSeconds(10), 187 RequestTimeSpan = TimeSpan.FromSeconds(10),
188 ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod 188 ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
189 }).Process); 189 }).Process);
190*/
191
192 MainServer.Instance.AddHTTPHandler(regionimage, OnHTTPGetMapImage);
190 MainServer.Instance.AddLLSDHandler( 193 MainServer.Instance.AddLLSDHandler(
191 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest); 194 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
192 195
@@ -197,13 +200,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
197 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; 200 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
198 m_scene.EventManager.OnRegionUp += OnRegionUp; 201 m_scene.EventManager.OnRegionUp += OnRegionUp;
199 202
200// StartThread(new object()); 203 StartThread(new object());
201 } 204 }
202 205
203 // this has to be called with a lock on m_scene 206 // this has to be called with a lock on m_scene
204 protected virtual void RemoveHandlers() 207 protected virtual void RemoveHandlers()
205 { 208 {
206// StopThread(); 209 StopThread();
207 210
208 m_scene.EventManager.OnRegionUp -= OnRegionUp; 211 m_scene.EventManager.OnRegionUp -= OnRegionUp;
209 m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; 212 m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent;
@@ -212,6 +215,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
212 m_scene.EventManager.OnNewClient -= OnNewClient; 215 m_scene.EventManager.OnNewClient -= OnNewClient;
213 m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; 216 m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
214 217
218 m_scene.UnregisterModuleInterface<IWorldMapModule>(this);
219
215 string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString(); 220 string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString();
216 regionimage = regionimage.Replace("-", ""); 221 regionimage = regionimage.Replace("-", "");
217 MainServer.Instance.RemoveLLSDHandler("/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), 222 MainServer.Instance.RemoveLLSDHandler("/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(),
@@ -222,12 +227,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
222 public void OnRegisterCaps(UUID agentID, Caps caps) 227 public void OnRegisterCaps(UUID agentID, Caps caps)
223 { 228 {
224 //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); 229 //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
225 string capsBase = "/CAPS/" + caps.CapsObjectPath; 230 string capspath = "/CAPS/" + UUID.Random();
226 caps.RegisterHandler( 231 caps.RegisterHandler(
227 "MapLayer", 232 "MapLayer",
228 new RestStreamHandler( 233 new RestStreamHandler(
229 "POST", 234 "POST",
230 capsBase + m_mapLayerPath, 235 capspath,
231 (request, path, param, httpRequest, httpResponse) 236 (request, path, param, httpRequest, httpResponse)
232 => MapLayerRequest(request, path, param, agentID, caps), 237 => MapLayerRequest(request, path, param, agentID, caps),
233 "MapLayer", 238 "MapLayer",
@@ -246,6 +251,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
246 public string MapLayerRequest(string request, string path, string param, 251 public string MapLayerRequest(string request, string path, string param,
247 UUID agentID, Caps caps) 252 UUID agentID, Caps caps)
248 { 253 {
254 // not sure about this....
255
249 //try 256 //try
250 // 257 //
251 //m_log.DebugFormat("[MAPLAYER]: path: {0}, param: {1}, agent:{2}", 258 //m_log.DebugFormat("[MAPLAYER]: path: {0}, param: {1}, agent:{2}",
@@ -261,54 +268,54 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
261 // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is 268 // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is
262 // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks. 269 // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks.
263 270
264 if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) 271 //if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048)
265 { 272 //{
266 ScenePresence avatarPresence = null; 273 // ScenePresence avatarPresence = null;
267 274
268 m_scene.TryGetScenePresence(agentID, out avatarPresence); 275 // m_scene.TryGetScenePresence(agentID, out avatarPresence);
269 276
270 if (avatarPresence != null) 277 // if (avatarPresence != null)
271 { 278 // {
272 bool lookup = false; 279 // bool lookup = false;
273 280
274 lock (cachedMapBlocks) 281 // lock (cachedMapBlocks)
275 { 282 // {
276 if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) 283 // if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch()))
277 { 284 // {
278 List<MapBlockData> mapBlocks; 285 // List<MapBlockData> mapBlocks;
279 286
280 mapBlocks = cachedMapBlocks; 287 // mapBlocks = cachedMapBlocks;
281 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); 288 // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
282 } 289 // }
283 else 290 // else
284 { 291 // {
285 lookup = true; 292 // lookup = true;
286 } 293 // }
287 } 294 // }
288 if (lookup) 295 // if (lookup)
289 { 296 // {
290 List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; 297 // List<MapBlockData> mapBlocks = new List<MapBlockData>(); ;
291 298
292 // Get regions that are within 8 regions of here 299 // List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
293 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 300 // (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize,
294 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 8), 301 // (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize,
295 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 8), 302 // (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize,
296 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 8), 303 // (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize);
297 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 8) ); 304 // foreach (GridRegion r in regions)
298 foreach (GridRegion r in regions) 305 // {
299 { 306 // MapBlockData block = new MapBlockData();
300 MapBlockData block = MapBlockFromGridRegion(r, 0); 307 // MapBlockFromGridRegion(block, r, 0);
301 mapBlocks.Add(block); 308 // mapBlocks.Add(block);
302 } 309 // }
303 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); 310 // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
304 311
305 lock (cachedMapBlocks) 312 // lock (cachedMapBlocks)
306 cachedMapBlocks = mapBlocks; 313 // cachedMapBlocks = mapBlocks;
307 314
308 cachedTime = Util.UnixTimeSinceEpoch(); 315 // cachedTime = Util.UnixTimeSinceEpoch();
309 } 316 // }
310 } 317 // }
311 } 318 //}
312 319
313 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); 320 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
314 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); 321 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
@@ -334,9 +341,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
334 /// <returns></returns> 341 /// <returns></returns>
335 protected static OSDMapLayer GetOSDMapLayerResponse() 342 protected static OSDMapLayer GetOSDMapLayerResponse()
336 { 343 {
344 // not sure about this.... 2048 or master 5000 and hack above?
345
337 OSDMapLayer mapLayer = new OSDMapLayer(); 346 OSDMapLayer mapLayer = new OSDMapLayer();
338 mapLayer.Right = 5000; 347 mapLayer.Right = 2048;
339 mapLayer.Top = 5000; 348 mapLayer.Top = 2048;
340 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); 349 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
341 350
342 return mapLayer; 351 return mapLayer;
@@ -365,6 +374,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
365 { 374 {
366 m_rootAgents.Remove(AgentId); 375 m_rootAgents.Remove(AgentId);
367 } 376 }
377 lock (m_mapBlockRequestEvent)
378 {
379 if (m_mapBlockRequests.ContainsKey(AgentId))
380 m_mapBlockRequests.Remove(AgentId);
381 }
368 } 382 }
369 #endregion 383 #endregion
370 384
@@ -379,14 +393,20 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
379 if (threadrunning) return; 393 if (threadrunning) return;
380 threadrunning = true; 394 threadrunning = true;
381 395
382// m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread"); 396 // m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread");
383 397
384 WorkManager.StartThread( 398 WorkManager.StartThread(
385 process, 399 process,
386 string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName), 400 string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName),
387 ThreadPriority.BelowNormal, 401 ThreadPriority.BelowNormal,
388 true, 402 true,
389 true); 403 false);
404 WorkManager.StartThread(
405 MapBlockSendThread,
406 string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName),
407 ThreadPriority.BelowNormal,
408 true,
409 false);
390 } 410 }
391 411
392 /// <summary> 412 /// <summary>
@@ -396,13 +416,29 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
396 { 416 {
397 MapRequestState st = new MapRequestState(); 417 MapRequestState st = new MapRequestState();
398 st.agentID = STOP_UUID; 418 st.agentID = STOP_UUID;
399 st.EstateID=0; 419 st.EstateID = 0;
400 st.flags=0; 420 st.flags = 0;
401 st.godlike=false; 421 st.godlike = false;
402 st.itemtype=0; 422 st.itemtype = 0;
403 st.regionhandle=0; 423 st.regionhandle = 0;
404 424
405 requests.Enqueue(st); 425 requests.Enqueue(st);
426
427 MapBlockRequestData req = new MapBlockRequestData();
428
429 req.client = null;
430 req.minX = 0;
431 req.maxX = 0;
432 req.minY = 0;
433 req.maxY = 0;
434 req.flags = 0;
435
436 lock (m_mapBlockRequestEvent)
437 {
438 m_mapBlockRequests[UUID.Zero] = new Queue<MapBlockRequestData>();
439 m_mapBlockRequests[UUID.Zero].Enqueue(req);
440 m_mapBlockRequestEvent.Set();
441 }
406 } 442 }
407 443
408 public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, 444 public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
@@ -415,315 +451,371 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
415 if (!m_rootAgents.Contains(remoteClient.AgentId)) 451 if (!m_rootAgents.Contains(remoteClient.AgentId))
416 return; 452 return;
417 } 453 }
454
455 // local or remote request?
456 if (regionhandle != 0 && regionhandle != m_scene.RegionInfo.RegionHandle)
457 {
458 // its Remote Map Item Request
459 // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes.
460 RequestMapItems("", remoteClient.AgentId, flags, EstateID, godlike, itemtype, regionhandle);
461 return;
462 }
463
418 uint xstart = 0; 464 uint xstart = 0;
419 uint ystart = 0; 465 uint ystart = 0;
420 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); 466 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
421 if (itemtype == (int)GridItemType.AgentLocations) 467
468 // its about this region...
469
470 List<mapItemReply> mapitems = new List<mapItemReply>();
471 mapItemReply mapitem = new mapItemReply();
472
473 // viewers only ask for green dots to each region now
474 // except at login with regionhandle 0
475 // possible on some other rare ocasions
476 // use previus hack of sending all items with the green dots
477
478 bool adultRegion;
479 if (regionhandle == 0)
422 { 480 {
423 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 481 switch (itemtype)
424 { 482 {
425 // Just requesting map info about the current, local region 483 case (int)GridItemType.AgentLocations:
426 int tc = Environment.TickCount; 484 // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots)
427 List<mapItemReply> mapitems = new List<mapItemReply>(); 485
428 mapItemReply mapitem = new mapItemReply(); 486 int tc = Environment.TickCount;
429 if (m_scene.GetRootAgentCount() <= 1) 487 if (m_scene.GetRootAgentCount() <= 1)
430 { 488 {
431 mapitem = new mapItemReply( 489 mapitem = new mapItemReply(
432 xstart + 1, 490 xstart + 1,
433 ystart + 1, 491 ystart + 1,
434 UUID.Zero, 492 UUID.Zero,
435 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), 493 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
436 0, 0); 494 0, 0);
437 mapitems.Add(mapitem); 495 mapitems.Add(mapitem);
438 } 496 }
439 else 497 else
440 {
441 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
442 { 498 {
499 m_scene.ForEachRootScenePresence(delegate (ScenePresence sp)
500 {
443 // Don't send a green dot for yourself 501 // Don't send a green dot for yourself
444 if (sp.UUID != remoteClient.AgentId) 502 if (sp.UUID != remoteClient.AgentId)
445 { 503 {
446 mapitem = new mapItemReply( 504 mapitem = new mapItemReply(
447 xstart + (uint)sp.AbsolutePosition.X, 505 xstart + (uint)sp.AbsolutePosition.X,
448 ystart + (uint)sp.AbsolutePosition.Y, 506 ystart + (uint)sp.AbsolutePosition.Y,
449 UUID.Zero, 507 UUID.Zero,
450 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), 508 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
451 1, 0); 509 1, 0);
452 mapitems.Add(mapitem); 510 mapitems.Add(mapitem);
453 } 511 }
454 }); 512 });
455 } 513 }
456 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); 514 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
457 } 515 break;
458 else
459 {
460 // Remote Map Item Request
461 516
462 // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. 517 case (int)GridItemType.Telehub:
463 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 518 // Service 1 (MAP_ITEM_TELEHUB)
464 } 519
465 } 520 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
466 else if (itemtype == (int)GridItemType.LandForSale) // Service 7 (MAP_ITEM_LAND_FOR_SALE) 521 if (sog != null)
467 {
468 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
469 {
470 // Parcels
471 ILandChannel landChannel = m_scene.LandChannel;
472 List<ILandObject> parcels = landChannel.AllParcels();
473
474 // Local Map Item Request
475 List<mapItemReply> mapitems = new List<mapItemReply>();
476 mapItemReply mapitem = new mapItemReply();
477 if ((parcels != null) && (parcels.Count >= 1))
478 {
479 foreach (ILandObject parcel_interface in parcels)
480 { 522 {
481 // Play it safe 523 mapitem = new mapItemReply(
482 if (!(parcel_interface is LandObject)) 524 xstart + (uint)sog.AbsolutePosition.X,
483 continue; 525 ystart + (uint)sog.AbsolutePosition.Y,
526 UUID.Zero,
527 sog.Name,
528 0, // color (not used)
529 0 // 0 = telehub / 1 = infohub
530 );
531 mapitems.Add(mapitem);
532 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
533 }
534 break;
484 535
485 LandObject land = (LandObject)parcel_interface; 536 case (int)GridItemType.AdultLandForSale:
486 LandData parcel = land.LandData; 537 case (int)GridItemType.LandForSale:
487 538
488 // Show land for sale 539 // Service 7 (MAP_ITEM_LAND_FOR_SALE)
489 if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale) 540 adultRegion = m_scene.RegionInfo.RegionSettings.Maturity == 2;
490 { 541 if (adultRegion)
491 Vector3 min = parcel.AABBMin; 542 {
492 Vector3 max = parcel.AABBMax; 543 if (itemtype == (int)GridItemType.LandForSale)
493 float x = (min.X+max.X)/2; 544 break;
494 float y = (min.Y+max.Y)/2; 545 }
546 else
547 {
548 if (itemtype == (int)GridItemType.AdultLandForSale)
549 break;
550 }
551
552 // Parcels
553 ILandChannel landChannel = m_scene.LandChannel;
554 List<ILandObject> parcels = landChannel.AllParcels();
495 555
496 mapitem = new mapItemReply( 556 if ((parcels != null) && (parcels.Count >= 1))
557 {
558 foreach (ILandObject parcel_interface in parcels)
559 {
560 // Play it safe
561 if (!(parcel_interface is LandObject))
562 continue;
563
564 LandObject land = (LandObject)parcel_interface;
565 LandData parcel = land.LandData;
566
567 // Show land for sale
568 if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
569 {
570 Vector3 min = parcel.AABBMin;
571 Vector3 max = parcel.AABBMax;
572 float x = (min.X + max.X) / 2;
573 float y = (min.Y + max.Y) / 2;
574 mapitem = new mapItemReply(
497 xstart + (uint)x, 575 xstart + (uint)x,
498 ystart + (uint)y, 576 ystart + (uint)y,
499 parcel.GlobalID, 577 parcel.GlobalID,
500 parcel.Name, 578 parcel.Name,
501 parcel.Area, 579 parcel.Area,
502 parcel.SalePrice 580 parcel.SalePrice
503 ); 581 );
504 mapitems.Add(mapitem); 582 mapitems.Add(mapitem);
583 }
505 } 584 }
506 } 585 }
507 } 586 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
508 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); 587 break;
509 }
510 else
511 {
512 // Remote Map Item Request
513 588
514 // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. 589 case (uint)GridItemType.PgEvent:
515 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 590 case (uint)GridItemType.MatureEvent:
591 case (uint)GridItemType.AdultEvent:
592 case (uint)GridItemType.Classified:
593 case (uint)GridItemType.Popular:
594 // TODO
595 // just dont not cry about them
596 break;
597
598 default:
599 // unkown map item type
600 m_log.DebugFormat("[WORLD MAP]: Unknown MapItem type {1}", itemtype);
601 break;
516 } 602 }
517 } 603 }
518 else if (itemtype == (int)GridItemType.Telehub) // Service 1 (MAP_ITEM_TELEHUB) 604 else
519 { 605 {
520 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 606 // send all items till we get a better fix
521 {
522 List<mapItemReply> mapitems = new List<mapItemReply>();
523 mapItemReply mapitem = new mapItemReply();
524 607
525 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); 608 // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots)
526 if (sog != null)
527 {
528 mapitem = new mapItemReply(
529 xstart + (uint)sog.AbsolutePosition.X,
530 ystart + (uint)sog.AbsolutePosition.Y,
531 UUID.Zero,
532 sog.Name,
533 0, // color (not used)
534 0 // 0 = telehub / 1 = infohub
535 );
536 mapitems.Add(mapitem);
537 609
538 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); 610 int tc = Environment.TickCount;
539 } 611 if (m_scene.GetRootAgentCount() <= 1)
612 {
613 mapitem = new mapItemReply(
614 xstart + 1,
615 ystart + 1,
616 UUID.Zero,
617 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
618 0, 0);
619 mapitems.Add(mapitem);
540 } 620 }
541 else 621 else
542 { 622 {
543 // Remote Map Item Request 623 m_scene.ForEachRootScenePresence(delegate (ScenePresence sp)
544 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 624 {
625 // Don't send a green dot for yourself
626 if (sp.UUID != remoteClient.AgentId)
627 {
628 mapitem = new mapItemReply(
629 xstart + (uint)sp.AbsolutePosition.X,
630 ystart + (uint)sp.AbsolutePosition.Y,
631 UUID.Zero,
632 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
633 1, 0);
634 mapitems.Add(mapitem);
635 }
636 });
545 } 637 }
546 } 638 remoteClient.SendMapItemReply(mapitems.ToArray(), 6, flags);
547 } 639 mapitems.Clear();
548 640
549 private int nAsyncRequests = 0; 641 // Service 1 (MAP_ITEM_TELEHUB)
550 /// <summary> 642
551 /// Processing thread main() loop for doing remote mapitem requests 643 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
552 /// </summary> 644 if (sog != null)
553 public void process()
554 {
555 //const int MAX_ASYNC_REQUESTS = 20;
556 try
557 {
558 while (true)
559 { 645 {
560 MapRequestState st = requests.Dequeue(1000); 646 mapitem = new mapItemReply(
647 xstart + (uint)sog.AbsolutePosition.X,
648 ystart + (uint)sog.AbsolutePosition.Y,
649 UUID.Zero,
650 sog.Name,
651 0, // color (not used)
652 0 // 0 = telehub / 1 = infohub
653 );
654 mapitems.Add(mapitem);
655 remoteClient.SendMapItemReply(mapitems.ToArray(), 1, flags);
656 mapitems.Clear();
657 }
561 658
562 // end gracefully 659 // Service 7 (MAP_ITEM_LAND_FOR_SALE)
563 if (st.agentID == STOP_UUID) 660
564 break; 661 uint its = 7;
662 if (m_scene.RegionInfo.RegionSettings.Maturity == 2)
663 its = 10;
664
665 // Parcels
666 ILandChannel landChannel = m_scene.LandChannel;
667 List<ILandObject> parcels = landChannel.AllParcels();
565 668
566 if (st.agentID != UUID.Zero) 669 if ((parcels != null) && (parcels.Count >= 1))
670 {
671 foreach (ILandObject parcel_interface in parcels)
567 { 672 {
568 bool dorequest = true; 673 // Play it safe
569 lock (m_rootAgents) 674 if (!(parcel_interface is LandObject))
570 { 675 continue;
571 if (!m_rootAgents.Contains(st.agentID)) 676
572 dorequest = false; 677 LandObject land = (LandObject)parcel_interface;
573 } 678 LandData parcel = land.LandData;
574 679
575 if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) 680 // Show land for sale
681 if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
576 { 682 {
577 while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break 683 Vector3 min = parcel.AABBMin;
578 Thread.Sleep(80); 684 Vector3 max = parcel.AABBMax;
579 685 float x = (min.X + max.X) / 2;
580 RequestMapItemsDelegate d = RequestMapItemsAsync; 686 float y = (min.Y + max.Y) / 2;
581 d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); 687 mapitem = new mapItemReply(
582 //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); 688 xstart + (uint)x,
583 //RequestMapItemsCompleted(response); 689 ystart + (uint)y,
584 Interlocked.Increment(ref nAsyncRequests); 690 parcel.GlobalID,
691 parcel.Name,
692 parcel.Area,
693 parcel.SalePrice
694 );
695 mapitems.Add(mapitem);
585 } 696 }
586 } 697 }
587 698 if(mapitems.Count >0)
588 Watchdog.UpdateThread(); 699 remoteClient.SendMapItemReply(mapitems.ToArray(), its, flags);
700 mapitems.Clear();
589 } 701 }
590 } 702 }
591 catch (Exception e)
592 {
593 m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e);
594 }
595
596 threadrunning = false;
597 Watchdog.RemoveThread();
598 } 703 }
599 704
600 const int MAX_ASYNC_REQUESTS = 20; 705 private int nAsyncRequests = 0;
601
602 /// <summary> 706 /// <summary>
603 /// Enqueues the map item request into the services throttle processing thread 707 /// Processing thread main() loop for doing remote mapitem requests
604 /// </summary> 708 /// </summary>
605 /// <param name="state"></param> 709 public void process()
606 public void EnqueueMapItemRequest(MapRequestState st)
607 { 710 {
711 const int MAX_ASYNC_REQUESTS = 20;
712 ScenePresence av = null;
713 MapRequestState st = null;
608 714
609 m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate 715 try
610 { 716 {
611 if (st.agentID != UUID.Zero) 717 while (true)
612 { 718 {
613 bool dorequest = true; 719 av = null;
614 lock (m_rootAgents) 720 st = null;
615 {
616 if (!m_rootAgents.Contains(st.agentID))
617 dorequest = false;
618 }
619 721
620 if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) 722 st = requests.Dequeue(4500);
621 { 723 Watchdog.UpdateThread();
622 if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
623 {
624 // AH!!! Recursive !
625 // Put this request back in the queue and return
626 EnqueueMapItemRequest(st);
627 return;
628 }
629 724
630 RequestMapItemsDelegate d = RequestMapItemsAsync; 725 if (st == null || st.agentID == UUID.Zero)
631 d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); 726 continue;
632 //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
633 //RequestMapItemsCompleted(response);
634 Interlocked.Increment(ref nAsyncRequests);
635 }
636 }
637 });
638 }
639 727
640 /// <summary> 728 // end gracefully
641 /// Sends the mapitem response to the IClientAPI 729 if (st.agentID == STOP_UUID)
642 /// </summary> 730 break;
643 /// <param name="response">The OSDMap Response for the mapitem</param>
644 private void RequestMapItemsCompleted(IAsyncResult iar)
645 {
646 AsyncResult result = (AsyncResult)iar;
647 RequestMapItemsDelegate icon = (RequestMapItemsDelegate)result.AsyncDelegate;
648 731
649 OSDMap response = (OSDMap)icon.EndInvoke(iar); 732 // agent gone?
650 733
651 Interlocked.Decrement(ref nAsyncRequests); 734 m_scene.TryGetScenePresence(st.agentID, out av);
735 if (av == null || av.IsChildAgent || av.IsDeleted || av.IsInTransit)
736 continue;
652 737
653 if (!response.ContainsKey("requestID")) 738 // region unreachable?
654 return; 739 if (m_blacklistedregions.Contains(st.regionhandle))
740 continue;
655 741
656 UUID requestID = response["requestID"].AsUUID(); 742 bool dorequest = true;
743 OSDMap responseMap = null;
657 744
658 if (requestID != UUID.Zero) 745 // check if we are already serving this region
659 { 746 lock (m_cachedRegionMapItemsResponses)
660 MapRequestState mrs = new MapRequestState();
661 mrs.agentID = UUID.Zero;
662 lock (m_openRequests)
663 {
664 if (m_openRequests.ContainsKey(requestID))
665 { 747 {
666 mrs = m_openRequests[requestID]; 748 if (m_cachedRegionMapItemsResponses.Contains(st.regionhandle))
667 m_openRequests.Remove(requestID); 749 {
750 m_cachedRegionMapItemsResponses.TryGetValue(st.regionhandle, out responseMap);
751 dorequest = false;
752 }
753 else
754 m_cachedRegionMapItemsResponses.Add(st.regionhandle, null, expireResponsesTime); // a bit more time for the access
668 } 755 }
669 }
670 756
671 if (mrs.agentID != UUID.Zero) 757 if (dorequest)
672 {
673 ScenePresence av = null;
674 m_scene.TryGetScenePresence(mrs.agentID, out av);
675 if (av != null)
676 { 758 {
677 if (response.ContainsKey(mrs.itemtype.ToString())) 759 // nothig for region, fire a request
760 Interlocked.Increment(ref nAsyncRequests);
761 MapRequestState rst = st;
762 Util.FireAndForget(x =>
678 { 763 {
679 List<mapItemReply> returnitems = new List<mapItemReply>(); 764 RequestMapItemsAsync(rst.agentID, rst.flags, rst.EstateID, rst.godlike, rst.itemtype, rst.regionhandle);
680 OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()]; 765 });
681 for (int i = 0; i < itemarray.Count; i++) 766 }
682 { 767 else
683 OSDMap mapitem = (OSDMap)itemarray[i]; 768 {
684 mapItemReply mi = new mapItemReply(); 769 // do we have the response?
685 mi.FromOSD(mapitem); 770 if (responseMap != null)
686 returnitems.Add(mi);
687 }
688 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
689 }
690
691 // Service 7 (MAP_ITEM_LAND_FOR_SALE)
692 uint itemtype = (uint)GridItemType.LandForSale;
693
694 if (response.ContainsKey(itemtype.ToString()))
695 { 771 {
696 List<mapItemReply> returnitems = new List<mapItemReply>(); 772 if(av!=null)
697 OSDArray itemarray = (OSDArray)response[itemtype.ToString()];
698 for (int i = 0; i < itemarray.Count; i++)
699 { 773 {
700 OSDMap mapitem = (OSDMap)itemarray[i]; 774 // this will mainly only send green dots now
701 mapItemReply mi = new mapItemReply(); 775 if (responseMap.ContainsKey(st.itemtype.ToString()))
702 mi.FromOSD(mapitem); 776 {
703 returnitems.Add(mi); 777 List<mapItemReply> returnitems = new List<mapItemReply>();
778 OSDArray itemarray = (OSDArray)responseMap[st.itemtype.ToString()];
779 for (int i = 0; i < itemarray.Count; i++)
780 {
781 OSDMap mapitem = (OSDMap)itemarray[i];
782 mapItemReply mi = new mapItemReply();
783 mi.x = (uint)mapitem["X"].AsInteger();
784 mi.y = (uint)mapitem["Y"].AsInteger();
785 mi.id = mapitem["ID"].AsUUID();
786 mi.Extra = mapitem["Extra"].AsInteger();
787 mi.Extra2 = mapitem["Extra2"].AsInteger();
788 mi.name = mapitem["Name"].AsString();
789 returnitems.Add(mi);
790 }
791 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), st.itemtype, st.flags & 0xffff);
792 }
704 } 793 }
705 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
706 } 794 }
707 795 else
708 // Service 1 (MAP_ITEM_TELEHUB)
709 itemtype = (uint)GridItemType.Telehub;
710
711 if (response.ContainsKey(itemtype.ToString()))
712 { 796 {
713 List<mapItemReply> returnitems = new List<mapItemReply>(); 797 // request still beeing processed, enqueue it back
714 OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; 798 requests.Enqueue(st);
715 for (int i = 0; i < itemarray.Count; i++) 799 if (requests.Count() < 3)
716 { 800 Thread.Sleep(100);
717 OSDMap mapitem = (OSDMap)itemarray[i];
718 mapItemReply mi = new mapItemReply();
719 mi.FromOSD(mapitem);
720 returnitems.Add(mi);
721 }
722 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
723 } 801 }
724 } 802 }
803
804 while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
805 {
806 Thread.Sleep(100);
807 Watchdog.UpdateThread();
808 }
725 } 809 }
726 } 810 }
811
812 catch (Exception e)
813 {
814 m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e);
815 }
816
817 threadrunning = false;
818 Watchdog.RemoveThread();
727 } 819 }
728 820
729 /// <summary> 821 /// <summary>
@@ -746,11 +838,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
746 st.godlike = godlike; 838 st.godlike = godlike;
747 st.itemtype = itemtype; 839 st.itemtype = itemtype;
748 st.regionhandle = regionhandle; 840 st.regionhandle = regionhandle;
749 EnqueueMapItemRequest(st); 841
842 requests.Enqueue(st);
750 } 843 }
751 844
752 private delegate OSDMap RequestMapItemsDelegate(UUID id, uint flags, 845 uint[] itemTypesForcedSend = new uint[] { 6, 1, 7, 10 }; // green dots, infohub, land sells
753 uint EstateID, bool godlike, uint itemtype, ulong regionhandle); 846
754 /// <summary> 847 /// <summary>
755 /// Does the actual remote mapitem request 848 /// Does the actual remote mapitem request
756 /// This should be called from an asynchronous thread 849 /// This should be called from an asynchronous thread
@@ -765,94 +858,55 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
765 /// <param name="itemtype">passed in from packet</param> 858 /// <param name="itemtype">passed in from packet</param>
766 /// <param name="regionhandle">Region we're looking up</param> 859 /// <param name="regionhandle">Region we're looking up</param>
767 /// <returns></returns> 860 /// <returns></returns>
768 private OSDMap RequestMapItemsAsync(UUID id, uint flags, 861 private void RequestMapItemsAsync(UUID id, uint flags,
769 uint EstateID, bool godlike, uint itemtype, ulong regionhandle) 862 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
770 { 863 {
771// m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype); 864 // m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype);
772 865
773 string httpserver = ""; 866 string httpserver = "";
774 bool blacklisted = false; 867 bool blacklisted = false;
775 lock (m_blacklistedregions)
776 {
777 if (m_blacklistedregions.ContainsKey(regionhandle))
778 {
779 if (Environment.TickCount > (m_blacklistedregions[regionhandle] + blacklistTimeout))
780 {
781 m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted region {0}", regionhandle);
782 868
783 m_blacklistedregions.Remove(regionhandle); 869 lock (m_blacklistedregions)
784 } 870 blacklisted = m_blacklistedregions.Contains(regionhandle);
785 else
786 blacklisted = true;
787 }
788 }
789 871
790 if (blacklisted) 872 if (blacklisted)
791 return new OSDMap(); 873 {
874 Interlocked.Decrement(ref nAsyncRequests);
875 return;
876 }
792 877
793 UUID requestID = UUID.Random(); 878 UUID requestID = UUID.Random();
794 lock (m_cachedRegionMapItemsAddress) 879 lock (m_cachedRegionMapItemsAddress)
795 { 880 m_cachedRegionMapItemsAddress.TryGetValue(regionhandle, out httpserver);
796 if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) 881
797 httpserver = m_cachedRegionMapItemsAddress[regionhandle]; 882 if (httpserver == null || httpserver.Length == 0)
798 }
799 if (httpserver.Length == 0)
800 { 883 {
801 uint x = 0, y = 0; 884 uint x = 0, y = 0;
802 Util.RegionHandleToWorldLoc(regionhandle, out x, out y); 885 Util.RegionHandleToWorldLoc(regionhandle, out x, out y);
886
803 GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); 887 GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
804 888
805 if (mreg != null) 889 if (mreg != null)
806 { 890 {
807 httpserver = mreg.ServerURI + "MAP/MapItems/" + regionhandle.ToString(); 891 httpserver = mreg.ServerURI + "MAP/MapItems/" + regionhandle.ToString();
808 lock (m_cachedRegionMapItemsAddress) 892 lock (m_cachedRegionMapItemsAddress)
809 { 893 m_cachedRegionMapItemsAddress.AddOrUpdate(regionhandle, httpserver, 2.0 * expireBlackListTime);
810 if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
811 m_cachedRegionMapItemsAddress.Add(regionhandle, httpserver);
812 }
813 }
814 else
815 {
816 lock (m_blacklistedregions)
817 {
818 if (!m_blacklistedregions.ContainsKey(regionhandle))
819 m_blacklistedregions.Add(regionhandle, Environment.TickCount);
820 }
821 //m_log.InfoFormat("[WORLD MAP]: Blacklisted region {0}", regionhandle.ToString());
822 } 894 }
823 } 895 }
824 896
825 blacklisted = false;
826 lock (m_blacklistedurls) 897 lock (m_blacklistedurls)
827 { 898 {
828 if (m_blacklistedurls.ContainsKey(httpserver)) 899 if (httpserver == null || httpserver.Length == 0 || m_blacklistedurls.Contains(httpserver))
829 { 900 {
830 if (Environment.TickCount > (m_blacklistedurls[httpserver] + blacklistTimeout)) 901 // Can't find the http server or its blocked
831 { 902 lock (m_blacklistedregions)
832 m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted URL {0}", httpserver); 903 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
833 904
834 m_blacklistedurls.Remove(httpserver); 905 Interlocked.Decrement(ref nAsyncRequests);
835 } 906 return;
836 else
837 blacklisted = true;
838 } 907 }
839 } 908 }
840 909
841 // Can't find the http server
842 if (httpserver.Length == 0 || blacklisted)
843 return new OSDMap();
844
845 MapRequestState mrs = new MapRequestState();
846 mrs.agentID = id;
847 mrs.EstateID = EstateID;
848 mrs.flags = flags;
849 mrs.godlike = godlike;
850 mrs.itemtype=itemtype;
851 mrs.regionhandle = regionhandle;
852
853 lock (m_openRequests)
854 m_openRequests.Add(requestID, mrs);
855
856 WebRequest mapitemsrequest = null; 910 WebRequest mapitemsrequest = null;
857 try 911 try
858 { 912 {
@@ -861,132 +915,144 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
861 catch (Exception e) 915 catch (Exception e)
862 { 916 {
863 m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e); 917 m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e);
864 return new OSDMap(); 918 Interlocked.Decrement(ref nAsyncRequests);
919 return;
865 } 920 }
866 921
867 mapitemsrequest.Method = "POST"; 922 mapitemsrequest.Method = "POST";
868 mapitemsrequest.ContentType = "application/xml+llsd"; 923 mapitemsrequest.ContentType = "application/xml+llsd";
869 OSDMap RAMap = new OSDMap();
870 924
925 OSDMap RAMap = new OSDMap();
871 // string RAMapString = RAMap.ToString(); 926 // string RAMapString = RAMap.ToString();
872 OSD LLSDofRAMap = RAMap; // RENAME if this works 927 OSD LLSDofRAMap = RAMap; // RENAME if this works
873 928
874 byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap); 929 byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap);
930
875 OSDMap responseMap = new OSDMap(); 931 OSDMap responseMap = new OSDMap();
876 responseMap["requestID"] = OSD.FromUUID(requestID);
877 932
878 Stream os = null;
879 try 933 try
880 { // send the Post 934 { // send the Post
881 mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send 935 mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send
882 os = mapitemsrequest.GetRequestStream(); 936 using (Stream os = mapitemsrequest.GetRequestStream())
883 os.Write(buffer, 0, buffer.Length); //Send it 937 os.Write(buffer, 0, buffer.Length); //Send it
884 //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from {0}", httpserver); 938 //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from {0}", httpserver);
885 } 939 }
886 catch (WebException ex) 940 catch (WebException ex)
887 { 941 {
888 m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message); 942 m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
889 responseMap["connect"] = OSD.FromBoolean(false); 943 m_log.WarnFormat("[WORLD MAP]: Blacklisted url {0}", httpserver);
890 lock (m_blacklistedurls) 944 lock (m_blacklistedurls)
891 { 945 m_blacklistedurls.AddOrUpdate(httpserver, 0, expireBlackListTime);
892 if (!m_blacklistedurls.ContainsKey(httpserver)) 946 lock (m_blacklistedregions)
893 m_blacklistedurls.Add(httpserver, Environment.TickCount); 947 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
894 }
895
896 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
897 948
898 return responseMap; 949 Interlocked.Decrement(ref nAsyncRequests);
950 return;
899 } 951 }
900 catch 952 catch
901 { 953 {
902 m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); 954 m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
903 responseMap["connect"] = OSD.FromBoolean(false); 955 Interlocked.Decrement(ref nAsyncRequests);
904 return responseMap; 956 return;
905 }
906 finally
907 {
908 if (os != null)
909 os.Dispose();
910 } 957 }
911 958
912 string response_mapItems_reply = null; 959 string response_mapItems_reply = null;
913 { 960 { // get the response
914 try 961 try
915 { 962 {
916 using (WebResponse webResponse = mapitemsrequest.GetResponse()) 963 using (WebResponse webResponse = mapitemsrequest.GetResponse())
917 { 964 {
918 if (webResponse != null) 965 if (webResponse != null)
919 { 966 {
920 using (Stream s = webResponse.GetResponseStream()) 967 using (StreamReader sr = new StreamReader(webResponse.GetResponseStream()))
921 using (StreamReader sr = new StreamReader(s)) 968 {
922 response_mapItems_reply = sr.ReadToEnd().Trim(); 969 response_mapItems_reply = sr.ReadToEnd().Trim();
970 }
923 } 971 }
924 else 972 else
925 { 973 {
926 return new OSDMap(); 974 Interlocked.Decrement(ref nAsyncRequests);
927 } 975 return;
928 } 976 }
977 }
929 } 978 }
930 catch (WebException) 979 catch (WebException)
931 { 980 {
932 responseMap["connect"] = OSD.FromBoolean(false);
933 lock (m_blacklistedurls) 981 lock (m_blacklistedurls)
934 { 982 m_blacklistedurls.AddOrUpdate(httpserver, 0, expireBlackListTime);
935 if (!m_blacklistedurls.ContainsKey(httpserver)) 983 lock (m_blacklistedregions)
936 m_blacklistedurls.Add(httpserver, Environment.TickCount); 984 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
937 }
938 985
939 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver); 986 m_log.WarnFormat("[WORLD MAP]: Blacklisted url {0}", httpserver);
940 987
941 return responseMap; 988 Interlocked.Decrement(ref nAsyncRequests);
989 return;
942 } 990 }
943 catch 991 catch
944 { 992 {
945 m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); 993 m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
946 responseMap["connect"] = OSD.FromBoolean(false);
947 lock (m_blacklistedregions) 994 lock (m_blacklistedregions)
948 { 995 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
949 if (!m_blacklistedregions.ContainsKey(regionhandle))
950 m_blacklistedregions.Add(regionhandle, Environment.TickCount);
951 }
952 996
953 return responseMap; 997 Interlocked.Decrement(ref nAsyncRequests);
998 return;
954 } 999 }
955 1000
956 OSD rezResponse = null;
957 try 1001 try
958 { 1002 {
959 rezResponse = OSDParser.DeserializeLLSDXml(response_mapItems_reply); 1003 responseMap = (OSDMap)OSDParser.DeserializeLLSDXml(response_mapItems_reply);
960
961 responseMap = (OSDMap)rezResponse;
962 responseMap["requestID"] = OSD.FromUUID(requestID);
963 } 1004 }
964 catch (Exception ex) 1005 catch (Exception ex)
965 { 1006 {
966 m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); 1007 m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message);
967 responseMap["connect"] = OSD.FromBoolean(false);
968
969 lock (m_blacklistedregions) 1008 lock (m_blacklistedregions)
970 { 1009 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
971 if (!m_blacklistedregions.ContainsKey(regionhandle))
972 m_blacklistedregions.Add(regionhandle, Environment.TickCount);
973 }
974 1010
975 return responseMap; 1011 Interlocked.Decrement(ref nAsyncRequests);
1012 return;
976 } 1013 }
977 } 1014 }
978 1015
979 if (!responseMap.ContainsKey(itemtype.ToString())) // remote sim doesnt have the stated region handle 1016 // cache the response that may include other valid items
1017 lock (m_cachedRegionMapItemsResponses)
1018 m_cachedRegionMapItemsResponses.AddOrUpdate(regionhandle, responseMap, expireResponsesTime);
1019
1020 flags &= 0xffff;
1021
1022 if (id != UUID.Zero)
980 { 1023 {
981 m_log.DebugFormat("[WORLD MAP]: Remote sim does not have the stated region. Blacklisting."); 1024 ScenePresence av = null;
982 lock (m_blacklistedregions) 1025 m_scene.TryGetScenePresence(id, out av);
1026 if (av != null && !av.IsChildAgent && !av.IsDeleted && !av.IsInTransit)
983 { 1027 {
984 if (!m_blacklistedregions.ContainsKey(regionhandle)) 1028 // send all the items or viewers will never ask for them, except green dots
985 m_blacklistedregions.Add(regionhandle, Environment.TickCount); 1029 foreach (uint itfs in itemTypesForcedSend)
1030 {
1031 if (responseMap.ContainsKey(itfs.ToString()))
1032 {
1033 List<mapItemReply> returnitems = new List<mapItemReply>();
1034// OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()];
1035 OSDArray itemarray = (OSDArray)responseMap[itfs.ToString()];
1036 for (int i = 0; i < itemarray.Count; i++)
1037 {
1038 OSDMap mapitem = (OSDMap)itemarray[i];
1039 mapItemReply mi = new mapItemReply();
1040 mi.x = (uint)mapitem["X"].AsInteger();
1041 mi.y = (uint)mapitem["Y"].AsInteger();
1042 mi.id = mapitem["ID"].AsUUID();
1043 mi.Extra = mapitem["Extra"].AsInteger();
1044 mi.Extra2 = mapitem["Extra2"].AsInteger();
1045 mi.name = mapitem["Name"].AsString();
1046 returnitems.Add(mi);
1047 }
1048// av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags);
1049 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itfs, flags);
1050 }
1051 }
986 } 1052 }
987 } 1053 }
988 1054
989 return responseMap; 1055 Interlocked.Decrement(ref nAsyncRequests);
990 } 1056 }
991 1057
992 /// <summary> 1058 /// <summary>
@@ -996,87 +1062,196 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
996 /// <param name="minY"></param> 1062 /// <param name="minY"></param>
997 /// <param name="maxX"></param> 1063 /// <param name="maxX"></param>
998 /// <param name="maxY"></param> 1064 /// <param name="maxY"></param>
999 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) 1065 public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
1000 { 1066 {
1001 if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible 1067// m_log.DebugFormat("[WoldMapModule] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
1068
1069 GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag);
1070 }
1071
1072 private const double SPAMBLOCKTIMEms = 300000; // 5 minutes
1073 private Dictionary<UUID,double> spamBlocked = new Dictionary<UUID,double>();
1074
1075 protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
1076 {
1077 // anti spam because of FireStorm 4.7.7 absurd request repeat rates
1078 // possible others
1079
1080 double now = Util.GetTimeStampMS();
1081 UUID agentID = remoteClient.AgentId;
1082
1083 lock (m_mapBlockRequestEvent)
1002 { 1084 {
1003 List<MapBlockData> response = new List<MapBlockData>(); 1085 if(spamBlocked.ContainsKey(agentID))
1004
1005 // this should return one mapblock at most. It is triggered by a click
1006 // on an unloaded square.
1007 // But make sure: Look whether the one we requested is in there
1008 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1009 (int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX),
1010 (int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) );
1011
1012 m_log.DebugFormat("[WORLD MAP MODULE] RequestMapBlocks min=<{0},{1}>, max=<{2},{3}>, flag={4}, cntFound={5}",
1013 minX, minY, maxX, maxY, flag.ToString("X"), regions.Count);
1014 if (regions != null)
1015 { 1086 {
1016 foreach (GridRegion r in regions) 1087 if(spamBlocked[agentID] < now &&
1088 (!m_mapBlockRequests.ContainsKey(agentID) ||
1089 m_mapBlockRequests[agentID].Count == 0 ))
1017 { 1090 {
1018 if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX) 1091 spamBlocked.Remove(agentID);
1019 && r.RegionLocY == Util.RegionToWorldLoc((uint)minY) ) 1092 m_log.DebugFormat("[WoldMapModule] RequestMapBlocks release spammer {0}", agentID);
1093 }
1094 else
1095 return new List<MapBlockData>();
1096 }
1097 else
1098 {
1099 // ugly slow expire spammers
1100 if(spamBlocked.Count > 0)
1101 {
1102 UUID k = UUID.Zero;
1103 bool expireone = false;
1104 foreach(UUID k2 in spamBlocked.Keys)
1020 { 1105 {
1021 // found it => add it to response 1106 if(spamBlocked[k2] < now &&
1022 // Version 2 viewers can handle the larger regions 1107 (!m_mapBlockRequests.ContainsKey(k2) ||
1023 if ((flag & 2) == 2) 1108 m_mapBlockRequests[k2].Count == 0 ))
1024 response.AddRange(Map2BlockFromGridRegion(r, flag)); 1109 {
1025 else 1110 m_log.DebugFormat("[WoldMapModule] RequestMapBlocks release spammer {0}", k2);
1026 response.Add(MapBlockFromGridRegion(r, flag)); 1111 k = k2;
1027 break; 1112 expireone = true;
1113 }
1114 break; // doing one at a time
1028 } 1115 }
1116 if(expireone)
1117 spamBlocked.Remove(k);
1029 } 1118 }
1030 } 1119 }
1031 1120
1032 if (response.Count == 0) 1121// m_log.DebugFormat("[WoldMapModule] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
1122
1123 MapBlockRequestData req = new MapBlockRequestData();
1124
1125 req.client = remoteClient;
1126 req.minX = minX;
1127 req.maxX = maxX;
1128 req.minY = minY;
1129 req.maxY = maxY;
1130 req.flags = flag;
1131
1132 if (!m_mapBlockRequests.ContainsKey(agentID))
1133 m_mapBlockRequests[agentID] = new Queue<MapBlockRequestData>();
1134 if(m_mapBlockRequests[agentID].Count < 150 )
1135 m_mapBlockRequests[agentID].Enqueue(req);
1136 else
1033 { 1137 {
1034 // response still empty => couldn't find the map-tile the user clicked on => tell the client 1138 spamBlocked[agentID] = now + SPAMBLOCKTIMEms;
1035 MapBlockData block = new MapBlockData(); 1139 m_log.DebugFormat("[WoldMapModule] RequestMapBlocks blocking spammer {0} for {1} s",agentID, SPAMBLOCKTIMEms/1000.0);
1036 block.X = (ushort)minX;
1037 block.Y = (ushort)minY;
1038 block.Access = (byte)SimAccess.Down; // means 'simulator is offline'
1039 // block.Access = (byte)SimAccess.NonExistent;
1040 response.Add(block);
1041 } 1140 }
1042 // The lower 16 bits are an unsigned int16 1141 m_mapBlockRequestEvent.Set();
1043 remoteClient.SendMapBlock(response, flag & 0xffff);
1044 } 1142 }
1045 else 1143
1144 return new List<MapBlockData>();
1145 }
1146
1147 protected void MapBlockSendThread()
1148 {
1149 List<MapBlockRequestData> thisRunData = new List<MapBlockRequestData>();
1150 while (true)
1046 { 1151 {
1047 // normal mapblock request. Use the provided values 1152 while(!m_mapBlockRequestEvent.WaitOne(4900))
1048 GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); 1153 {
1154 Watchdog.UpdateThread();
1155 if(m_scene == null)
1156 return;
1157 }
1158 Watchdog.UpdateThread();
1159 lock (m_mapBlockRequestEvent)
1160 {
1161 int total = 0;
1162 foreach (Queue<MapBlockRequestData> q in m_mapBlockRequests.Values)
1163 {
1164 if (q.Count > 0)
1165 thisRunData.Add(q.Dequeue());
1166
1167 total += q.Count;
1168 }
1169
1170 if (total == 0)
1171 m_mapBlockRequestEvent.Reset();
1172 }
1173
1174 if(thisRunData.Count > 0)
1175 {
1176 foreach (MapBlockRequestData req in thisRunData)
1177 {
1178 // Null client stops thread
1179 if (req.client == null)
1180 return;
1181
1182 GetAndSendBlocksInternal(req.client, req.minX, req.minY, req.maxX, req.maxY, req.flags);
1183 }
1184
1185 thisRunData.Clear();
1186 }
1187
1188 Thread.Sleep(50);
1049 } 1189 }
1050 } 1190 }
1051 1191
1052 protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) 1192 protected virtual List<MapBlockData> GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
1053 { 1193 {
1194 List<MapBlockData> allBlocks = new List<MapBlockData>();
1054 List<MapBlockData> mapBlocks = new List<MapBlockData>(); 1195 List<MapBlockData> mapBlocks = new List<MapBlockData>();
1055 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 1196 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1056 (int)Util.RegionToWorldLoc((uint)(minX - 4)), (int)Util.RegionToWorldLoc((uint)(maxX + 4)), 1197 minX * (int)Constants.RegionSize,
1057 (int)Util.RegionToWorldLoc((uint)(minY - 4)), (int)Util.RegionToWorldLoc((uint)(maxY + 4)) ); 1198 maxX * (int)Constants.RegionSize,
1058 //m_log.DebugFormat("{0} GetAndSendBlocks. min=<{1},{2}>, max=<{3},{4}>, cntFound={5}", 1199 minY * (int)Constants.RegionSize,
1059 // LogHeader, minX, minY, maxX, maxY, regions.Count); 1200 maxY * (int)Constants.RegionSize);
1201
1202 // only send a negative answer for a single region request
1203 // corresponding to a click on the map. Current viewers
1204 // keep displaying "loading.." without this
1205 if (regions.Count == 0 && (flag & 0x10000) != 0 && minX == maxX && minY == maxY)
1206 {
1207 MapBlockData block = new MapBlockData();
1208 block.X = (ushort)minX;
1209 block.Y = (ushort)minY;
1210 block.MapImageId = UUID.Zero;
1211 block.Access = (byte)SimAccess.NonExistent;
1212 allBlocks.Add(block);
1213 mapBlocks.Add(block);
1214 remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
1215 return allBlocks;
1216 }
1217
1218 flag &= 0xffff;
1219
1060 foreach (GridRegion r in regions) 1220 foreach (GridRegion r in regions)
1061 { 1221 {
1062 // Version 2 viewers can handle the larger regions 1222 if (r == null)
1063 if ((flag & 2) == 2) 1223 continue;
1064 mapBlocks.AddRange(Map2BlockFromGridRegion(r, flag)); 1224 MapBlockData block = new MapBlockData();
1065 else 1225 MapBlockFromGridRegion(block, r, flag);
1066 mapBlocks.Add(MapBlockFromGridRegion(r, flag)); 1226 mapBlocks.Add(block);
1227 allBlocks.Add(block);
1228
1229 if (mapBlocks.Count >= 10)
1230 {
1231 remoteClient.SendMapBlock(mapBlocks, flag);
1232 mapBlocks.Clear();
1233 Thread.Sleep(50);
1234 }
1067 } 1235 }
1068 remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); 1236 if (mapBlocks.Count > 0)
1237 remoteClient.SendMapBlock(mapBlocks, flag);
1069 1238
1070 return mapBlocks; 1239 return allBlocks;
1071 } 1240 }
1072 1241
1073 // Fill a passed MapBlockData from a GridRegion 1242 public void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag)
1074 public MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag)
1075 { 1243 {
1076 MapBlockData block = new MapBlockData(); 1244 if (r == null)
1245 {
1246 // we should not get here ??
1247// block.Access = (byte)SimAccess.Down; this is for a grid reply on r
1248 block.Access = (byte)SimAccess.NonExistent;
1249 block.MapImageId = UUID.Zero;
1250 return;
1251 }
1077 1252
1078 block.Access = r.Access; 1253 block.Access = r.Access;
1079 switch (flag & 0xffff) 1254 switch (flag)
1080 { 1255 {
1081 case 0: 1256 case 0:
1082 block.MapImageId = r.TerrainImage; 1257 block.MapImageId = r.TerrainImage;
@@ -1089,50 +1264,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1089 break; 1264 break;
1090 } 1265 }
1091 block.Name = r.RegionName; 1266 block.Name = r.RegionName;
1092 block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX); 1267 block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
1093 block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY); 1268 block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
1094 block.SizeX = (ushort) r.RegionSizeX; 1269 block.SizeX = (ushort)r.RegionSizeX;
1095 block.SizeY = (ushort) r.RegionSizeY; 1270 block.SizeY = (ushort)r.RegionSizeY;
1096 1271
1097 return block;
1098 } 1272 }
1099 1273
1100 public List<MapBlockData> Map2BlockFromGridRegion(GridRegion r, uint flag)
1101 {
1102 List<MapBlockData> blocks = new List<MapBlockData>();
1103 MapBlockData block = new MapBlockData();
1104 if (r == null)
1105 {
1106 block.Access = (byte)SimAccess.Down;
1107 block.MapImageId = UUID.Zero;
1108 blocks.Add(block);
1109 }
1110 else
1111 {
1112 block.Access = r.Access;
1113 switch (flag & 0xffff)
1114 {
1115 case 0:
1116 block.MapImageId = r.TerrainImage;
1117 break;
1118 case 2:
1119 block.MapImageId = r.ParcelImage;
1120 break;
1121 default:
1122 block.MapImageId = UUID.Zero;
1123 break;
1124 }
1125 block.Name = r.RegionName;
1126 block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
1127 block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
1128 block.SizeX = (ushort)r.RegionSizeX;
1129 block.SizeY = (ushort)r.RegionSizeY;
1130 blocks.Add(block);
1131 }
1132 return blocks;
1133 }
1134
1135
1136 public Hashtable OnHTTPThrottled(Hashtable keysvals) 1274 public Hashtable OnHTTPThrottled(Hashtable keysvals)
1137 { 1275 {
1138 Hashtable reply = new Hashtable(); 1276 Hashtable reply = new Hashtable();
@@ -1145,67 +1283,71 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1145 1283
1146 public Hashtable OnHTTPGetMapImage(Hashtable keysvals) 1284 public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
1147 { 1285 {
1148 m_log.Debug("[WORLD MAP]: Sending map image jpeg");
1149 Hashtable reply = new Hashtable(); 1286 Hashtable reply = new Hashtable();
1150 int statuscode = 200; 1287 int statuscode = 200;
1151 byte[] jpeg = new byte[0]; 1288 byte[] jpeg = new byte[0];
1152 1289
1153 if (myMapImageJPEG.Length == 0) 1290 if (m_scene.RegionInfo.RegionSettings.TerrainImageID != UUID.Zero)
1154 { 1291 {
1155 MemoryStream imgstream = null; 1292 m_log.Debug("[WORLD MAP]: Sending map image jpeg");
1156 Bitmap mapTexture = new Bitmap(1,1);
1157 ManagedImage managedImage;
1158 Image image = (Image)mapTexture;
1159 1293
1160 try 1294 if (myMapImageJPEG.Length == 0)
1161 { 1295 {
1162 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data 1296 MemoryStream imgstream = null;
1297 Bitmap mapTexture = new Bitmap(1, 1);
1298 ManagedImage managedImage;
1299 Image image = (Image)mapTexture;
1300
1301 try
1302 {
1303 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data
1163 1304
1164 imgstream = new MemoryStream(); 1305 imgstream = new MemoryStream();
1165 1306
1166 // non-async because we know we have the asset immediately. 1307 // non-async because we know we have the asset immediately.
1167 AssetBase mapasset = m_scene.AssetService.Get(m_scene.RegionInfo.RegionSettings.TerrainImageID.ToString()); 1308 AssetBase mapasset = m_scene.AssetService.Get(m_scene.RegionInfo.RegionSettings.TerrainImageID.ToString());
1168 1309
1169 // Decode image to System.Drawing.Image 1310 // Decode image to System.Drawing.Image
1170 if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image)) 1311 if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image))
1171 { 1312 {
1172 // Save to bitmap 1313 // Save to bitmap
1173 mapTexture = new Bitmap(image); 1314 mapTexture = new Bitmap(image);
1174 1315
1175 EncoderParameters myEncoderParameters = new EncoderParameters(); 1316 EncoderParameters myEncoderParameters = new EncoderParameters();
1176 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); 1317 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L);
1177 1318
1178 // Save bitmap to stream 1319 // Save bitmap to stream
1179 mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters); 1320 mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters);
1180 1321
1181 // Write the stream to a byte array for output 1322 // Write the stream to a byte array for output
1182 jpeg = imgstream.ToArray(); 1323 jpeg = imgstream.ToArray();
1183 myMapImageJPEG = jpeg; 1324 myMapImageJPEG = jpeg;
1325 }
1184 } 1326 }
1185 } 1327 catch (Exception)
1186 catch (Exception) 1328 {
1187 { 1329 // Dummy!
1188 // Dummy! 1330 m_log.Warn("[WORLD MAP]: Unable to generate Map image");
1189 m_log.Warn("[WORLD MAP]: Unable to generate Map image"); 1331 }
1190 } 1332 finally
1191 finally 1333 {
1192 { 1334 // Reclaim memory, these are unmanaged resources
1193 // Reclaim memory, these are unmanaged resources 1335 // If we encountered an exception, one or more of these will be null
1194 // If we encountered an exception, one or more of these will be null 1336 if (mapTexture != null)
1195 if (mapTexture != null) 1337 mapTexture.Dispose();
1196 mapTexture.Dispose();
1197 1338
1198 if (image != null) 1339 if (image != null)
1199 image.Dispose(); 1340 image.Dispose();
1200 1341
1201 if (imgstream != null) 1342 if (imgstream != null)
1202 imgstream.Dispose(); 1343 imgstream.Dispose();
1344 }
1345 }
1346 else
1347 {
1348 // Use cached version so we don't have to loose our mind
1349 jpeg = myMapImageJPEG;
1203 } 1350 }
1204 }
1205 else
1206 {
1207 // Use cached version so we don't have to loose our mind
1208 jpeg = myMapImageJPEG;
1209 } 1351 }
1210 1352
1211 reply["str_response_string"] = Convert.ToBase64String(jpeg); 1353 reply["str_response_string"] = Convert.ToBase64String(jpeg);
@@ -1267,22 +1409,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1267 1409
1268 foreach (GridRegion r in regions) 1410 foreach (GridRegion r in regions)
1269 { 1411 {
1270 MapBlockData mapBlock = MapBlockFromGridRegion(r, 0); 1412 MapBlockData mapBlock = new MapBlockData();
1413 MapBlockFromGridRegion(mapBlock, r, 0);
1271 AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); 1414 AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
1272 1415
1273 if (texAsset != null) 1416 if (texAsset != null)
1274 { 1417 {
1275 textures.Add(texAsset); 1418 textures.Add(texAsset);
1276 } 1419 }
1277 //else
1278 //{
1279 // // WHAT?!? This doesn't seem right. Commenting (diva)
1280 // texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
1281 // if (texAsset != null)
1282 // {
1283 // textures.Add(texAsset);
1284 // }
1285 //}
1286 } 1420 }
1287 1421
1288 foreach (AssetBase asset in textures) 1422 foreach (AssetBase asset in textures)
@@ -1308,6 +1442,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1308 1442
1309 mapTexture.Save(exportPath, ImageFormat.Jpeg); 1443 mapTexture.Save(exportPath, ImageFormat.Jpeg);
1310 1444
1445 g.Dispose();
1446 mapTexture.Dispose();
1447 sea.Dispose();
1448
1311 m_log.InfoFormat( 1449 m_log.InfoFormat(
1312 "[WORLD MAP]: Successfully exported world map for {0} to {1}", 1450 "[WORLD MAP]: Successfully exported world map for {0} to {1}",
1313 m_scene.RegionInfo.RegionName, exportPath); 1451 m_scene.RegionInfo.RegionName, exportPath);
@@ -1320,17 +1458,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1320 if (consoleScene != null && consoleScene != m_scene) 1458 if (consoleScene != null && consoleScene != m_scene)
1321 return; 1459 return;
1322 1460
1323 if (m_mapImageGenerator == null) 1461 GenerateMaptile();
1324 {
1325 Console.WriteLine("No map image generator available for {0}", m_scene.Name);
1326 return;
1327 }
1328
1329 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
1330 {
1331 GenerateMaptile(mapbmp);
1332 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
1333 }
1334 } 1462 }
1335 1463
1336 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) 1464 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
@@ -1338,9 +1466,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1338 uint xstart = 0; 1466 uint xstart = 0;
1339 uint ystart = 0; 1467 uint ystart = 0;
1340 1468
1341 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); 1469 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
1342 // m_log.DebugFormat("{0} HandleRemoteMapItemRequest. loc=<{1},{2}>",
1343 // LogHeader, Util.WorldToRegionLoc(xstart), Util.WorldToRegionLoc(ystart));
1344 1470
1345 // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots) 1471 // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots)
1346 1472
@@ -1362,8 +1488,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1362 } 1488 }
1363 else 1489 else
1364 { 1490 {
1365 OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount()); 1491 OSDArray responsearr = new OSDArray(); // Don't preallocate. MT (m_scene.GetRootAgentCount());
1366 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) 1492 m_scene.ForEachRootScenePresence(delegate (ScenePresence sp)
1367 { 1493 {
1368 OSDMap responsemapdata = new OSDMap(); 1494 OSDMap responsemapdata = new OSDMap();
1369 responsemapdata["X"] = OSD.FromInteger((int)(xstart + sp.AbsolutePosition.X)); 1495 responsemapdata["X"] = OSD.FromInteger((int)(xstart + sp.AbsolutePosition.X));
@@ -1377,28 +1503,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1377 responsemap["6"] = responsearr; 1503 responsemap["6"] = responsearr;
1378 } 1504 }
1379 1505
1380 // Service 7 (MAP_ITEM_LAND_FOR_SALE) 1506 // Service 7/10 (MAP_ITEM_LAND_FOR_SALE/ADULT)
1381 1507
1382 ILandChannel landChannel = m_scene.LandChannel; 1508 ILandChannel landChannel = m_scene.LandChannel;
1383 List<ILandObject> parcels = landChannel.AllParcels(); 1509 List<ILandObject> parcels = landChannel.AllParcels();
1384 1510
1385 if ((parcels == null) || (parcels.Count == 0)) 1511 if ((parcels != null) && (parcels.Count >= 0))
1386 { 1512 {
1387 OSDMap responsemapdata = new OSDMap(); 1513 OSDArray responsearr = new OSDArray(parcels.Count);
1388 responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1));
1389 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1));
1390 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
1391 responsemapdata["Name"] = OSD.FromString("");
1392 responsemapdata["Extra"] = OSD.FromInteger(0);
1393 responsemapdata["Extra2"] = OSD.FromInteger(0);
1394 OSDArray responsearr = new OSDArray();
1395 responsearr.Add(responsemapdata);
1396
1397 responsemap["7"] = responsearr;
1398 }
1399 else
1400 {
1401 OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount());
1402 foreach (ILandObject parcel_interface in parcels) 1514 foreach (ILandObject parcel_interface in parcels)
1403 { 1515 {
1404 // Play it safe 1516 // Play it safe
@@ -1413,8 +1525,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1413 { 1525 {
1414 Vector3 min = parcel.AABBMin; 1526 Vector3 min = parcel.AABBMin;
1415 Vector3 max = parcel.AABBMax; 1527 Vector3 max = parcel.AABBMax;
1416 float x = (min.X+max.X)/2; 1528 float x = (min.X + max.X) / 2;
1417 float y = (min.Y+max.Y)/2; 1529 float y = (min.Y + max.Y) / 2;
1418 1530
1419 OSDMap responsemapdata = new OSDMap(); 1531 OSDMap responsemapdata = new OSDMap();
1420 responsemapdata["X"] = OSD.FromInteger((int)(xstart + x)); 1532 responsemapdata["X"] = OSD.FromInteger((int)(xstart + x));
@@ -1427,7 +1539,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1427 responsearr.Add(responsemapdata); 1539 responsearr.Add(responsemapdata);
1428 } 1540 }
1429 } 1541 }
1430 responsemap["7"] = responsearr; 1542
1543 if(responsearr.Count > 0)
1544 {
1545 if(m_scene.RegionInfo.RegionSettings.Maturity == 2)
1546 responsemap["10"] = responsearr;
1547 else
1548 responsemap["7"] = responsearr;
1549 }
1431 } 1550 }
1432 1551
1433 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) 1552 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
@@ -1459,55 +1578,110 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1459 if (m_scene.Heightmap == null) 1578 if (m_scene.Heightmap == null)
1460 return; 1579 return;
1461 1580
1581 if (m_mapImageGenerator == null)
1582 {
1583 Console.WriteLine("No map image generator available for {0}", m_scene.Name);
1584 return;
1585 }
1462 m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name); 1586 m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name);
1463 1587
1464 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile()) 1588 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
1465 { 1589 {
1466 // V1 (This Module)
1467 GenerateMaptile(mapbmp); 1590 GenerateMaptile(mapbmp);
1468 1591
1469 // v2/3 (MapImageServiceModule) 1592 if (m_mapImageServiceModule != null)
1470 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp); 1593 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
1471 } 1594 }
1472 } 1595 }
1473 1596
1474 private void GenerateMaptile(Bitmap mapbmp) 1597 private void GenerateMaptile(Bitmap mapbmp)
1475 { 1598 {
1476 byte[] data; 1599 bool needRegionSave = false;
1477 1600
1478 try 1601 // remove old assets
1602 UUID lastID = m_scene.RegionInfo.RegionSettings.TerrainImageID;
1603 if (lastID != UUID.Zero)
1479 { 1604 {
1480 data = OpenJPEG.EncodeFromImage(mapbmp, true); 1605 m_scene.AssetService.Delete(lastID.ToString());
1606 m_scene.RegionInfo.RegionSettings.TerrainImageID = UUID.Zero;
1607 myMapImageJPEG = new byte[0];
1608 needRegionSave = true;
1481 } 1609 }
1482 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke 1610
1611 lastID = m_scene.RegionInfo.RegionSettings.ParcelImageID;
1612 if (lastID != UUID.Zero)
1483 { 1613 {
1484 m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e); 1614 m_scene.AssetService.Delete(lastID.ToString());
1485 return; 1615 m_scene.RegionInfo.RegionSettings.ParcelImageID = UUID.Zero;
1616 needRegionSave = true;
1486 } 1617 }
1487 1618
1488 byte[] overlay = GenerateOverlay(); 1619 if(mapbmp != null)
1620 {
1621 try
1622 {
1623 byte[] data;
1624
1625 // if large region limit its size since new viewers will not use it
1626 // but it is still usable for ossl
1627 if(m_scene.RegionInfo.RegionSizeX > Constants.RegionSize ||
1628 m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1629 {
1630 int bx = mapbmp.Width;
1631 int by = mapbmp.Height;
1632 int mb = bx;
1633 if(mb < by)
1634 mb = by;
1635 if(mb > Constants.RegionSize && mb > 0)
1636 {
1637 float scale = (float)Constants.RegionSize/(float)mb;
1638 Size newsize = new Size();
1639 newsize.Width = (int)(bx * scale);
1640 newsize.Height = (int)(by * scale);
1641
1642 using(Bitmap scaledbmp = new Bitmap(mapbmp,newsize))
1643 data = OpenJPEG.EncodeFromImage(scaledbmp, true);
1644 }
1645 else
1646 data = OpenJPEG.EncodeFromImage(mapbmp, true);
1647 }
1648 else
1649 data = OpenJPEG.EncodeFromImage(mapbmp, true);
1650
1651 if (data != null && data.Length > 0)
1652 {
1653 UUID terrainImageID = UUID.Random();
1654
1655 AssetBase asset = new AssetBase(
1656 terrainImageID,
1657 "terrainImage_" + m_scene.RegionInfo.RegionID.ToString(),
1658 (sbyte)AssetType.Texture,
1659 m_scene.RegionInfo.RegionID.ToString());
1660 asset.Data = data;
1661 asset.Description = m_scene.RegionInfo.RegionName;
1662 asset.Temporary = false;
1663 asset.Flags = AssetFlags.Maptile;
1489 1664
1490 UUID terrainImageID = UUID.Random(); 1665 // Store the new one
1491 UUID parcelImageID = UUID.Zero; 1666 m_log.DebugFormat("[WORLD MAP]: Storing map image {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName);
1492 1667
1493 AssetBase asset = new AssetBase( 1668 m_scene.AssetService.Store(asset);
1494 terrainImageID,
1495 "terrainImage_" + m_scene.RegionInfo.RegionID.ToString(),
1496 (sbyte)AssetType.Texture,
1497 m_scene.RegionInfo.RegionID.ToString());
1498 asset.Data = data;
1499 asset.Description = m_scene.RegionInfo.RegionName;
1500 asset.Temporary = false;
1501 asset.Flags = AssetFlags.Maptile;
1502 1669
1503 // Store the new one 1670 m_scene.RegionInfo.RegionSettings.TerrainImageID = terrainImageID;
1504 m_log.DebugFormat("[WORLD MAP]: Storing map tile {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName); 1671 needRegionSave = true;
1505 1672 }
1506 m_scene.AssetService.Store(asset); 1673 }
1674 catch (Exception e)
1675 {
1676 m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e);
1677 }
1678 }
1507 1679
1680 // V2/3 still seem to need this, or we are missing something somewhere
1681 byte[] overlay = GenerateOverlay();
1508 if (overlay != null) 1682 if (overlay != null)
1509 { 1683 {
1510 parcelImageID = UUID.Random(); 1684 UUID parcelImageID = UUID.Random();
1511 1685
1512 AssetBase parcels = new AssetBase( 1686 AssetBase parcels = new AssetBase(
1513 parcelImageID, 1687 parcelImageID,
@@ -1520,20 +1694,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1520 parcels.Flags = AssetFlags.Maptile; 1694 parcels.Flags = AssetFlags.Maptile;
1521 1695
1522 m_scene.AssetService.Store(parcels); 1696 m_scene.AssetService.Store(parcels);
1697
1698 m_scene.RegionInfo.RegionSettings.ParcelImageID = parcelImageID;
1699 needRegionSave = true;
1523 } 1700 }
1524 1701
1525 // Switch to the new one 1702 if (needRegionSave)
1526 UUID lastTerrainImageID = m_scene.RegionInfo.RegionSettings.TerrainImageID; 1703 m_scene.RegionInfo.RegionSettings.Save();
1527 UUID lastParcelImageID = m_scene.RegionInfo.RegionSettings.ParcelImageID;
1528 m_scene.RegionInfo.RegionSettings.TerrainImageID = terrainImageID;
1529 m_scene.RegionInfo.RegionSettings.ParcelImageID = parcelImageID;
1530 m_scene.RegionInfo.RegionSettings.Save();
1531
1532 // Delete the old one
1533 // m_log.DebugFormat("[WORLDMAP]: Deleting old map tile {0}", lastTerrainImageID);
1534 m_scene.AssetService.Delete(lastTerrainImageID.ToString());
1535 if (lastParcelImageID != UUID.Zero)
1536 m_scene.AssetService.Delete(lastParcelImageID.ToString());
1537 } 1704 }
1538 1705
1539 private void MakeRootAgent(ScenePresence avatar) 1706 private void MakeRootAgent(ScenePresence avatar)
@@ -1553,6 +1720,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1553 { 1720 {
1554 m_rootAgents.Remove(avatar.UUID); 1721 m_rootAgents.Remove(avatar.UUID);
1555 } 1722 }
1723
1724 lock (m_mapBlockRequestEvent)
1725 {
1726 if (m_mapBlockRequests.ContainsKey(avatar.UUID))
1727 m_mapBlockRequests.Remove(avatar.UUID);
1728 }
1556 } 1729 }
1557 1730
1558 public void OnRegionUp(GridRegion otherRegion) 1731 public void OnRegionUp(GridRegion otherRegion)
@@ -1562,46 +1735,67 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1562 1735
1563 lock (m_blacklistedregions) 1736 lock (m_blacklistedregions)
1564 { 1737 {
1565 if (!m_blacklistedregions.ContainsKey(regionhandle)) 1738 if (m_blacklistedregions.Contains(regionhandle))
1566 m_blacklistedregions.Remove(regionhandle); 1739 m_blacklistedregions.Remove(regionhandle);
1567 } 1740 }
1568 1741
1569 lock (m_blacklistedurls) 1742 lock (m_blacklistedurls)
1570 { 1743 {
1571 if (m_blacklistedurls.ContainsKey(httpserver)) 1744 if (m_blacklistedurls.Contains(httpserver))
1572 m_blacklistedurls.Remove(httpserver); 1745 m_blacklistedurls.Remove(httpserver);
1573 } 1746 }
1574 1747
1575 lock (m_cachedRegionMapItemsAddress) 1748 lock (m_cachedRegionMapItemsAddress)
1576 { 1749 {
1577 if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) 1750 m_cachedRegionMapItemsAddress.AddOrUpdate(regionhandle,
1578 m_cachedRegionMapItemsAddress.Remove(regionhandle); 1751 httpserver, 5.0 * expireBlackListTime);
1579 } 1752 }
1580 } 1753 }
1581 1754
1582 private Byte[] GenerateOverlay() 1755 private Byte[] GenerateOverlay()
1583 { 1756 {
1757 int landTileSize = LandManagementModule.LandUnit;
1758
1584 // These need to be ints for bitmap generation 1759 // These need to be ints for bitmap generation
1585 int regionSizeX = (int)m_scene.RegionInfo.RegionSizeX; 1760 int regionSizeX = (int)m_scene.RegionInfo.RegionSizeX;
1586 int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY;
1587
1588 int landTileSize = LandManagementModule.LandUnit;
1589 int regionLandTilesX = regionSizeX / landTileSize; 1761 int regionLandTilesX = regionSizeX / landTileSize;
1762
1763 int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY;
1590 int regionLandTilesY = regionSizeY / landTileSize; 1764 int regionLandTilesY = regionSizeY / landTileSize;
1591 1765
1592 using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY)) 1766 bool landForSale = false;
1767 ILandObject land;
1768
1769 // scan terrain avoiding potencial merges of large bitmaps
1770 //TODO create the sell bitmap at landchannel / landmaster ?
1771 // and auction also, still not suported
1772
1773 bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY];
1774 for (int x = 0, xx = 0; x < regionLandTilesX; x++ ,xx += landTileSize)
1593 { 1775 {
1594 bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY]; 1776 for (int y = 0, yy = 0; y < regionLandTilesY; y++, yy += landTileSize)
1595 for (int x = 0; x < regionLandTilesX; x++)
1596 { 1777 {
1597 for (int y = 0; y < regionLandTilesY; y++) 1778 land = m_scene.LandChannel.GetLandObject(xx, yy);
1779 if (land != null && (land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
1780 {
1781 saleBitmap[x, y] = true;
1782 landForSale = true;
1783 }
1784 else
1598 saleBitmap[x, y] = false; 1785 saleBitmap[x, y] = false;
1599 } 1786 }
1787 }
1600 1788
1601 bool landForSale = false; 1789 if (!landForSale)
1790 {
1791 m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
1792 return null;
1793 }
1602 1794
1603 List<ILandObject> parcels = m_scene.LandChannel.AllParcels(); 1795 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
1604 1796
1797 using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY))
1798 {
1605 Color background = Color.FromArgb(0, 0, 0, 0); 1799 Color background = Color.FromArgb(0, 0, 0, 0);
1606 1800
1607 using (Graphics g = Graphics.FromImage(overlay)) 1801 using (Graphics g = Graphics.FromImage(overlay))
@@ -1609,36 +1803,19 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1609 using (SolidBrush transparent = new SolidBrush(background)) 1803 using (SolidBrush transparent = new SolidBrush(background))
1610 g.FillRectangle(transparent, 0, 0, regionSizeX, regionSizeY); 1804 g.FillRectangle(transparent, 0, 0, regionSizeX, regionSizeY);
1611 1805
1612 foreach (ILandObject land in parcels) 1806 // make it a bit transparent
1807 using (SolidBrush yellow = new SolidBrush(Color.FromArgb(192, 249, 223, 9)))
1613 { 1808 {
1614 // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags); 1809 for (int x = 0; x < regionLandTilesX; x++)
1615 if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
1616 { 1810 {
1617 landForSale = true; 1811 for (int y = 0; y < regionLandTilesY; y++)
1618
1619 saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap());
1620 }
1621 }
1622
1623 if (!landForSale)
1624 {
1625 m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
1626 return null;
1627 }
1628
1629 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
1630
1631 using (SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)))
1632 {
1633 for (int x = 0 ; x < regionLandTilesX ; x++)
1634 {
1635 for (int y = 0 ; y < regionLandTilesY ; y++)
1636 { 1812 {
1637 if (saleBitmap[x, y]) 1813 if (saleBitmap[x, y])
1638 g.FillRectangle( 1814 g.FillRectangle(
1639 yellow, x * landTileSize, 1815 yellow,
1640 regionSizeX - landTileSize - (y * landTileSize), 1816 x * landTileSize,
1641 landTileSize, 1817 regionSizeX - landTileSize - (y * landTileSize),
1818 landTileSize,
1642 landTileSize); 1819 landTileSize);
1643 } 1820 }
1644 } 1821 }
@@ -1659,7 +1836,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1659 } 1836 }
1660 } 1837 }
1661 1838
1662 public struct MapRequestState 1839 public class MapRequestState
1663 { 1840 {
1664 public UUID agentID; 1841 public UUID agentID;
1665 public uint flags; 1842 public uint flags;
@@ -1668,4 +1845,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1668 public uint itemtype; 1845 public uint itemtype;
1669 public ulong regionhandle; 1846 public ulong regionhandle;
1670 } 1847 }
1848
1849 public struct MapBlockRequestData
1850 {
1851 public IClientAPI client;
1852 public int minX;
1853 public int minY;
1854 public int maxX;
1855 public int maxY;
1856 public uint flags;
1857 }
1671} 1858}