aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs905
1 files changed, 0 insertions, 905 deletions
diff --git a/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs
deleted file mode 100644
index 37b4547..0000000
--- a/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs
+++ /dev/null
@@ -1,905 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.IO;
34using System.Net;
35using System.Reflection;
36using System.Threading;
37using OpenMetaverse;
38using OpenMetaverse.Imaging;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using OpenSim.Framework;
43using OpenSim.Framework.Communications.Cache;
44using OpenSim.Framework.Communications.Capabilities;
45using OpenSim.Framework.Servers;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Framework.Scenes.Types;
49using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
50
51using OSD = OpenMetaverse.StructuredData.OSD;
52using OSDMap = OpenMetaverse.StructuredData.OSDMap;
53using OSDArray = OpenMetaverse.StructuredData.OSDArray;
54
55namespace OpenSim.Region.Environment.Modules.World.WorldMap
56{
57 public class WorldMapModule : IRegionModule
58 {
59 private static readonly ILog m_log =
60 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
62 private static readonly string m_mapLayerPath = "0001/";
63
64 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
65
66 //private IConfig m_config;
67 protected Scene m_scene;
68 private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
69 private int cachedTime = 0;
70 private byte[] myMapImageJPEG;
71 protected bool m_Enabled = false;
72 private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>();
73 private Dictionary<string, int> m_blacklistedurls = new Dictionary<string, int>();
74 private Dictionary<ulong, int> m_blacklistedregions = new Dictionary<ulong, int>();
75 private Dictionary<ulong, string> m_cachedRegionMapItemsAddress = new Dictionary<ulong, string>();
76 private List<UUID> m_rootAgents = new List<UUID>();
77 private Thread mapItemReqThread;
78 private volatile bool threadrunning = false;
79
80 //private int CacheRegionsDistance = 256;
81
82 #region IRegionModule Members
83
84 public virtual void Initialise(Scene scene, IConfigSource config)
85 {
86 IConfig startupConfig = config.Configs["Startup"];
87 if (startupConfig.GetString("WorldMapModule", "WorldMap") ==
88 "WorldMap")
89 m_Enabled = true;
90
91 if (!m_Enabled)
92 return;
93
94 m_scene = scene;
95 }
96
97 public virtual void PostInitialise()
98 {
99 if (m_Enabled)
100 AddHandlers();
101 }
102
103 public virtual void Close()
104 {
105 }
106
107 public virtual string Name
108 {
109 get { return "WorldMapModule"; }
110 }
111
112 public bool IsSharedModule
113 {
114 get { return false; }
115 }
116
117 #endregion
118
119 protected virtual void AddHandlers()
120 {
121 myMapImageJPEG = new byte[0];
122
123 string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString();
124 regionimage = regionimage.Replace("-", "");
125 m_log.Info("[WORLD MAP]: JPEG Map location: http://" + m_scene.RegionInfo.ExternalEndPoint.Address.ToString() + ":" + m_scene.RegionInfo.HttpPort.ToString() + "/index.php?method=" + regionimage);
126
127 m_scene.CommsManager.HttpServer.AddHTTPHandler(regionimage, OnHTTPGetMapImage);
128 m_scene.CommsManager.HttpServer.AddLLSDHandler(
129 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
130
131 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
132 m_scene.EventManager.OnNewClient += OnNewClient;
133 m_scene.EventManager.OnClientClosed += ClientLoggedOut;
134 m_scene.EventManager.OnMakeChildAgent += MakeChildAgent;
135 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
136 }
137
138 public void OnRegisterCaps(UUID agentID, Caps caps)
139 {
140 //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
141 string capsBase = "/CAPS/" + caps.CapsObjectPath;
142 caps.RegisterHandler("MapLayer",
143 new RestStreamHandler("POST", capsBase + m_mapLayerPath,
144 delegate(string request, string path, string param,
145 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
146 {
147 return MapLayerRequest(request, path, param,
148 agentID, caps);
149 }));
150 }
151
152 /// <summary>
153 /// Callback for a map layer request
154 /// </summary>
155 /// <param name="request"></param>
156 /// <param name="path"></param>
157 /// <param name="param"></param>
158 /// <param name="agentID"></param>
159 /// <param name="caps"></param>
160 /// <returns></returns>
161 public string MapLayerRequest(string request, string path, string param,
162 UUID agentID, Caps caps)
163 {
164 //try
165 //{
166 //m_log.DebugFormat("[MAPLAYER]: request: {0}, path: {1}, param: {2}, agent:{3}",
167 //request, path, param,agentID.ToString());
168
169 // this is here because CAPS map requests work even beyond the 10,000 limit.
170 ScenePresence avatarPresence = null;
171
172 m_scene.TryGetAvatar(agentID, out avatarPresence);
173
174 if (avatarPresence != null)
175 {
176 bool lookup = false;
177
178 lock (cachedMapBlocks)
179 {
180 if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch()))
181 {
182 List<MapBlockData> mapBlocks;
183
184 mapBlocks = cachedMapBlocks;
185 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
186 }
187 else
188 {
189 lookup = true;
190 }
191 }
192 if (lookup)
193 {
194 List<MapBlockData> mapBlocks;
195
196 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks((int)m_scene.RegionInfo.RegionLocX - 8, (int)m_scene.RegionInfo.RegionLocY - 8, (int)m_scene.RegionInfo.RegionLocX + 8, (int)m_scene.RegionInfo.RegionLocY + 8);
197 avatarPresence.ControllingClient.SendMapBlock(mapBlocks,0);
198
199 lock (cachedMapBlocks)
200 cachedMapBlocks = mapBlocks;
201
202 cachedTime = Util.UnixTimeSinceEpoch();
203 }
204 }
205 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
206 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
207 return mapResponse.ToString();
208 }
209
210 /// <summary>
211 ///
212 /// </summary>
213 /// <param name="mapReq"></param>
214 /// <returns></returns>
215 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
216 {
217 m_log.Debug("[WORLD MAP]: MapLayer Request in region: " + m_scene.RegionInfo.RegionName);
218 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
219 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
220 return mapResponse;
221 }
222
223 /// <summary>
224 ///
225 /// </summary>
226 /// <returns></returns>
227 protected static OSDMapLayer GetOSDMapLayerResponse()
228 {
229 OSDMapLayer mapLayer = new OSDMapLayer();
230 mapLayer.Right = 5000;
231 mapLayer.Top = 5000;
232 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
233
234 return mapLayer;
235 }
236 #region EventHandlers
237
238 /// <summary>
239 /// Registered for event
240 /// </summary>
241 /// <param name="client"></param>
242 private void OnNewClient(IClientAPI client)
243 {
244 client.OnRequestMapBlocks += RequestMapBlocks;
245 client.OnMapItemRequest += HandleMapItemRequest;
246 }
247
248 /// <summary>
249 /// Client logged out, check to see if there are any more root agents in the simulator
250 /// If not, stop the mapItemRequest Thread
251 /// Event handler
252 /// </summary>
253 /// <param name="AgentId">AgentID that logged out</param>
254 private void ClientLoggedOut(UUID AgentId)
255 {
256 List<ScenePresence> presences = m_scene.GetAvatars();
257 int rootcount = 0;
258 for (int i=0;i<presences.Count;i++)
259 {
260 if (presences[i] != null)
261 {
262 if (!presences[i].IsChildAgent)
263 rootcount++;
264 }
265 }
266 if (rootcount <= 1)
267 StopThread();
268
269 lock (m_rootAgents)
270 {
271 if (m_rootAgents.Contains(AgentId))
272 {
273 m_rootAgents.Remove(AgentId);
274 }
275 }
276 }
277 #endregion
278
279 /// <summary>
280 /// Starts the MapItemRequest Thread
281 /// Note that this only gets started when there are actually agents in the region
282 /// Additionally, it gets stopped when there are none.
283 /// </summary>
284 /// <param name="o"></param>
285 private void StartThread(object o)
286 {
287 if (threadrunning) return;
288 threadrunning = true;
289 m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread");
290 mapItemReqThread = new Thread(new ThreadStart(process));
291 mapItemReqThread.IsBackground = true;
292 mapItemReqThread.Name = "MapItemRequestThread";
293 mapItemReqThread.Priority = ThreadPriority.BelowNormal;
294 mapItemReqThread.SetApartmentState(ApartmentState.MTA);
295 mapItemReqThread.Start();
296 ThreadTracker.Add(mapItemReqThread);
297 }
298
299 /// <summary>
300 /// Enqueues a 'stop thread' MapRequestState. Causes the MapItemRequest thread to end
301 /// </summary>
302 private void StopThread()
303 {
304 MapRequestState st = new MapRequestState();
305 st.agentID=UUID.Zero;
306 st.EstateID=0;
307 st.flags=0;
308 st.godlike=false;
309 st.itemtype=0;
310 st.regionhandle=0;
311
312 requests.Enqueue(st);
313 }
314
315 public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
316 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
317 {
318 lock (m_rootAgents)
319 {
320 if (!m_rootAgents.Contains(remoteClient.AgentId))
321 return;
322 }
323 uint xstart = 0;
324 uint ystart = 0;
325 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
326 if (itemtype == 6) // we only sevice 6 right now (avatar green dots)
327 {
328 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
329 {
330 // Local Map Item Request
331 List<ScenePresence> avatars = m_scene.GetAvatars();
332 int tc = System.Environment.TickCount;
333 List<mapItemReply> mapitems = new List<mapItemReply>();
334 mapItemReply mapitem = new mapItemReply();
335 if (avatars.Count == 0 || avatars.Count == 1)
336 {
337 mapitem = new mapItemReply();
338 mapitem.x = (uint)(xstart + 1);
339 mapitem.y = (uint)(ystart + 1);
340 mapitem.id = UUID.Zero;
341 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
342 mapitem.Extra = 0;
343 mapitem.Extra2 = 0;
344 mapitems.Add(mapitem);
345 }
346 else
347 {
348 foreach (ScenePresence av in avatars)
349 {
350 // Don't send a green dot for yourself
351 if (av.UUID != remoteClient.AgentId)
352 {
353 mapitem = new mapItemReply();
354 mapitem.x = (uint)(xstart + av.AbsolutePosition.X);
355 mapitem.y = (uint)(ystart + av.AbsolutePosition.Y);
356 mapitem.id = UUID.Zero;
357 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
358 mapitem.Extra = 1;
359 mapitem.Extra2 = 0;
360 mapitems.Add(mapitem);
361 }
362 }
363 }
364 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
365 }
366 else
367 {
368 // Remote Map Item Request
369
370 // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes.
371 // Note that we only start up a remote mapItem Request thread if there's users who could
372 // be making requests
373 if (!threadrunning)
374 {
375 m_log.Warn("[WORLD MAP]: Starting new remote request thread manually. This means that AvatarEnteringParcel never fired! This needs to be fixed! Don't Mantis this, as the developers can see it in this message");
376 StartThread(new object());
377 }
378
379 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
380 }
381 }
382 }
383
384 /// <summary>
385 /// Processing thread main() loop for doing remote mapitem requests
386 /// </summary>
387 public void process()
388 {
389 try
390 {
391 while (true)
392 {
393 MapRequestState st = requests.Dequeue();
394
395 // end gracefully
396 if (st.agentID == UUID.Zero)
397 {
398 ThreadTracker.Remove(mapItemReqThread);
399 break;
400 }
401
402 bool dorequest = true;
403 lock (m_rootAgents)
404 {
405 if (!m_rootAgents.Contains(st.agentID))
406 dorequest = false;
407 }
408
409 if (dorequest)
410 {
411 OSDMap response = RequestMapItemsAsync("", st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
412 RequestMapItemsCompleted(response);
413 }
414 }
415 }
416 catch (Exception e)
417 {
418 m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e);
419 }
420
421 threadrunning = false;
422 }
423
424 /// <summary>
425 /// Enqueues the map item request into the processing thread
426 /// </summary>
427 /// <param name="state"></param>
428 public void EnqueueMapItemRequest(MapRequestState state)
429 {
430 requests.Enqueue(state);
431 }
432
433 /// <summary>
434 /// Sends the mapitem response to the IClientAPI
435 /// </summary>
436 /// <param name="response">The OSDMap Response for the mapitem</param>
437 private void RequestMapItemsCompleted(OSDMap response)
438 {
439 UUID requestID = response["requestID"].AsUUID();
440
441 if (requestID != UUID.Zero)
442 {
443 MapRequestState mrs = new MapRequestState();
444 mrs.agentID = UUID.Zero;
445 lock (m_openRequests)
446 {
447 if (m_openRequests.ContainsKey(requestID))
448 {
449 mrs = m_openRequests[requestID];
450 m_openRequests.Remove(requestID);
451 }
452 }
453
454 if (mrs.agentID != UUID.Zero)
455 {
456 ScenePresence av = null;
457 m_scene.TryGetAvatar(mrs.agentID, out av);
458 if (av != null)
459 {
460 if (response.ContainsKey(mrs.itemtype.ToString()))
461 {
462 List<mapItemReply> returnitems = new List<mapItemReply>();
463 OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()];
464 for (int i = 0; i < itemarray.Count; i++)
465 {
466 OSDMap mapitem = (OSDMap)itemarray[i];
467 mapItemReply mi = new mapItemReply();
468 mi.x = (uint)mapitem["X"].AsInteger();
469 mi.y = (uint)mapitem["Y"].AsInteger();
470 mi.id = mapitem["ID"].AsUUID();
471 mi.Extra = mapitem["Extra"].AsInteger();
472 mi.Extra2 = mapitem["Extra2"].AsInteger();
473 mi.name = mapitem["Name"].AsString();
474 returnitems.Add(mi);
475 }
476 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
477 }
478 }
479 }
480 }
481 }
482
483 /// <summary>
484 /// Enqueue the MapItem request for remote processing
485 /// </summary>
486 /// <param name="httpserver">blank string, we discover this in the process</param>
487 /// <param name="id">Agent ID that we are making this request on behalf</param>
488 /// <param name="flags">passed in from packet</param>
489 /// <param name="EstateID">passed in from packet</param>
490 /// <param name="godlike">passed in from packet</param>
491 /// <param name="itemtype">passed in from packet</param>
492 /// <param name="regionhandle">Region we're looking up</param>
493 public void RequestMapItems(string httpserver, UUID id, uint flags,
494 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
495 {
496 MapRequestState st = new MapRequestState();
497 st.agentID = id;
498 st.flags = flags;
499 st.EstateID = EstateID;
500 st.godlike = godlike;
501 st.itemtype = itemtype;
502 st.regionhandle = regionhandle;
503 EnqueueMapItemRequest(st);
504 }
505
506 /// <summary>
507 /// Does the actual remote mapitem request
508 /// This should be called from an asynchronous thread
509 /// Request failures get blacklisted until region restart so we don't
510 /// continue to spend resources trying to contact regions that are down.
511 /// </summary>
512 /// <param name="httpserver">blank string, we discover this in the process</param>
513 /// <param name="id">Agent ID that we are making this request on behalf</param>
514 /// <param name="flags">passed in from packet</param>
515 /// <param name="EstateID">passed in from packet</param>
516 /// <param name="godlike">passed in from packet</param>
517 /// <param name="itemtype">passed in from packet</param>
518 /// <param name="regionhandle">Region we're looking up</param>
519 /// <returns></returns>
520 private OSDMap RequestMapItemsAsync(string httpserver, UUID id, uint flags,
521 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
522 {
523 bool blacklisted = false;
524 lock (m_blacklistedregions)
525 {
526 if (m_blacklistedregions.ContainsKey(regionhandle))
527 blacklisted = true;
528 }
529
530 if (blacklisted)
531 return new OSDMap();
532
533 UUID requestID = UUID.Random();
534 lock (m_cachedRegionMapItemsAddress)
535 {
536 if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
537 httpserver = m_cachedRegionMapItemsAddress[regionhandle];
538 }
539 if (httpserver.Length == 0)
540 {
541 RegionInfo mreg = m_scene.SceneGridService.RequestNeighbouringRegionInfo(regionhandle);
542
543 if (mreg != null)
544 {
545 httpserver = "http://" + mreg.ExternalEndPoint.Address.ToString() + ":" + mreg.HttpPort + "/MAP/MapItems/" + regionhandle.ToString();
546 lock (m_cachedRegionMapItemsAddress)
547 {
548 if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
549 m_cachedRegionMapItemsAddress.Add(regionhandle, httpserver);
550 }
551 }
552 else
553 {
554 lock (m_blacklistedregions)
555 {
556 if (!m_blacklistedregions.ContainsKey(regionhandle))
557 m_blacklistedregions.Add(regionhandle, System.Environment.TickCount);
558 }
559 m_log.InfoFormat("[WORLD MAP]: Blacklisted region {0}", regionhandle.ToString());
560 }
561 }
562
563 blacklisted = false;
564 lock (m_blacklistedurls)
565 {
566 if (m_blacklistedurls.ContainsKey(httpserver))
567 blacklisted = true;
568 }
569
570 // Can't find the http server
571 if (httpserver.Length == 0 || blacklisted)
572 return new OSDMap();
573
574 MapRequestState mrs = new MapRequestState();
575 mrs.agentID = id;
576 mrs.EstateID = EstateID;
577 mrs.flags = flags;
578 mrs.godlike = godlike;
579 mrs.itemtype=itemtype;
580 mrs.regionhandle = regionhandle;
581
582 lock (m_openRequests)
583 m_openRequests.Add(requestID, mrs);
584
585 WebRequest mapitemsrequest = WebRequest.Create(httpserver);
586 mapitemsrequest.Method = "POST";
587 mapitemsrequest.ContentType = "application/xml+llsd";
588 OSDMap RAMap = new OSDMap();
589
590 // string RAMapString = RAMap.ToString();
591 OSD LLSDofRAMap = RAMap; // RENAME if this works
592
593 byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap);
594 OSDMap responseMap = new OSDMap();
595 responseMap["requestID"] = OSD.FromUUID(requestID);
596
597 Stream os = null;
598 try
599 { // send the Post
600 mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send
601 os = mapitemsrequest.GetRequestStream();
602 os.Write(buffer, 0, buffer.Length); //Send it
603 os.Close();
604 //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from Sim {0}", httpserver);
605 }
606 catch (WebException ex)
607 {
608 m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
609 responseMap["connect"] = OSD.FromBoolean(false);
610 lock (m_blacklistedurls)
611 {
612 if (!m_blacklistedurls.ContainsKey(httpserver))
613 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
614 }
615
616 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
617
618 return responseMap;
619 }
620
621 string response_mapItems_reply = null;
622 { // get the response
623 try
624 {
625 WebResponse webResponse = mapitemsrequest.GetResponse();
626 if (webResponse != null)
627 {
628 StreamReader sr = new StreamReader(webResponse.GetResponseStream());
629 response_mapItems_reply = sr.ReadToEnd().Trim();
630 }
631 else
632 {
633 return new OSDMap();
634 }
635 }
636 catch (WebException)
637 {
638 responseMap["connect"] = OSD.FromBoolean(false);
639 lock (m_blacklistedurls)
640 {
641 if (!m_blacklistedurls.ContainsKey(httpserver))
642 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
643 }
644
645 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
646
647 return responseMap;
648 }
649 OSD rezResponse = null;
650 try
651 {
652 rezResponse = OSDParser.DeserializeLLSDXml(response_mapItems_reply);
653
654 responseMap = (OSDMap)rezResponse;
655 responseMap["requestID"] = OSD.FromUUID(requestID);
656 }
657 catch (Exception)
658 {
659 //m_log.InfoFormat("[OGP]: exception on parse of rez reply {0}", ex.Message);
660 responseMap["connect"] = OSD.FromBoolean(false);
661
662 return responseMap;
663 }
664 }
665 return responseMap;
666 }
667
668 /// <summary>
669 /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates
670 /// </summary>
671 /// <param name="minX"></param>
672 /// <param name="minY"></param>
673 /// <param name="maxX"></param>
674 /// <param name="maxY"></param>
675 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
676 {
677 List<MapBlockData> mapBlocks;
678 if ((flag & 0x10000) != 0) // user clicked on the map a tile that isn't visible
679 {
680 List<MapBlockData> response = new List<MapBlockData>();
681
682 // this should return one mapblock at most. But make sure: Look whether the one we requested is in there
683 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY);
684 if (mapBlocks != null)
685 {
686 foreach (MapBlockData block in mapBlocks)
687 {
688 if (block.X == minX && block.Y == minY)
689 {
690 // found it => add it to response
691 response.Add(block);
692 break;
693 }
694 }
695 }
696
697 if (response.Count == 0)
698 {
699 // response still empty => couldn't find the map-tile the user clicked on => tell the client
700 MapBlockData block = new MapBlockData();
701 block.X = (ushort)minX;
702 block.Y = (ushort)minY;
703 block.Access = 254; // == not there
704 response.Add(block);
705 }
706 remoteClient.SendMapBlock(response, 0);
707 }
708 else
709 {
710 // normal mapblock request. Use the provided values
711 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX - 4, minY - 4, maxX + 4, maxY + 4);
712 remoteClient.SendMapBlock(mapBlocks, flag);
713 }
714 }
715
716 public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
717 {
718 m_log.Debug("[WORLD MAP]: Sending map image jpeg");
719 Hashtable reply = new Hashtable();
720 int statuscode = 200;
721 byte[] jpeg = new byte[0];
722
723 if (myMapImageJPEG.Length == 0)
724 {
725 MemoryStream imgstream = new MemoryStream();
726 Bitmap mapTexture = new Bitmap(1,1);
727 ManagedImage managedImage;
728 Image image = (Image)mapTexture;
729
730 try
731 {
732 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data
733
734 imgstream = new MemoryStream();
735
736 // non-async because we know we have the asset immediately.
737 AssetBase mapasset = m_scene.AssetCache.GetAsset(m_scene.RegionInfo.lastMapUUID, true);
738
739 // Decode image to System.Drawing.Image
740 if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image))
741 {
742 // Save to bitmap
743 mapTexture = new Bitmap(image);
744
745 EncoderParameters myEncoderParameters = new EncoderParameters();
746 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L);
747
748 // Save bitmap to stream
749 mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters);
750
751 // Write the stream to a byte array for output
752 jpeg = imgstream.ToArray();
753 myMapImageJPEG = jpeg;
754 }
755 }
756 catch (Exception)
757 {
758 // Dummy!
759 m_log.Warn("[WORLD MAP]: Unable to generate Map image");
760 }
761 finally
762 {
763 // Reclaim memory, these are unmanaged resources
764 mapTexture.Dispose();
765 image.Dispose();
766 imgstream.Close();
767 imgstream.Dispose();
768 }
769 }
770 else
771 {
772 // Use cached version so we don't have to loose our mind
773 jpeg = myMapImageJPEG;
774 }
775
776 reply["str_response_string"] = Convert.ToBase64String(jpeg);
777 reply["int_response_code"] = statuscode;
778 reply["content_type"] = "image/jpeg";
779
780 return reply;
781 }
782
783 // From msdn
784 private static ImageCodecInfo GetEncoderInfo(String mimeType)
785 {
786 ImageCodecInfo[] encoders;
787 encoders = ImageCodecInfo.GetImageEncoders();
788 for (int j = 0; j < encoders.Length; ++j)
789 {
790 if (encoders[j].MimeType == mimeType)
791 return encoders[j];
792 }
793 return null;
794 }
795
796 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
797 {
798 uint xstart = 0;
799 uint ystart = 0;
800
801 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
802
803 OSDMap responsemap = new OSDMap();
804 List<ScenePresence> avatars = m_scene.GetAvatars();
805 OSDArray responsearr = new OSDArray(avatars.Count);
806 OSDMap responsemapdata = new OSDMap();
807 int tc = System.Environment.TickCount;
808 /*
809 foreach (ScenePresence av in avatars)
810 {
811 responsemapdata = new OSDMap();
812 responsemapdata["X"] = OSD.FromInteger((int)(xstart + av.AbsolutePosition.X));
813 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + av.AbsolutePosition.Y));
814 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
815 responsemapdata["Name"] = OSD.FromString("TH");
816 responsemapdata["Extra"] = OSD.FromInteger(0);
817 responsemapdata["Extra2"] = OSD.FromInteger(0);
818 responsearr.Add(responsemapdata);
819 }
820 responsemap["1"] = responsearr;
821 */
822 if (avatars.Count == 0)
823 {
824 responsemapdata = new OSDMap();
825 responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1));
826 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1));
827 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
828 responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
829 responsemapdata["Extra"] = OSD.FromInteger(0);
830 responsemapdata["Extra2"] = OSD.FromInteger(0);
831 responsearr.Add(responsemapdata);
832
833 responsemap["6"] = responsearr;
834 }
835 else
836 {
837 responsearr = new OSDArray(avatars.Count);
838 foreach (ScenePresence av in avatars)
839 {
840 responsemapdata = new OSDMap();
841 responsemapdata["X"] = OSD.FromInteger((int)(xstart + av.AbsolutePosition.X));
842 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + av.AbsolutePosition.Y));
843 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
844 responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
845 responsemapdata["Extra"] = OSD.FromInteger(1);
846 responsemapdata["Extra2"] = OSD.FromInteger(0);
847 responsearr.Add(responsemapdata);
848 }
849 responsemap["6"] = responsearr;
850 }
851 return responsemap;
852 }
853
854 private void MakeRootAgent(ScenePresence avatar)
855 {
856 // You may ask, why this is in a threadpool to start with..
857 // The reason is so we don't cause the thread to freeze waiting
858 // for the 1 second it costs to start a thread manually.
859 if (!threadrunning)
860 ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartThread));
861
862 lock (m_rootAgents)
863 {
864 if (!m_rootAgents.Contains(avatar.UUID))
865 {
866 m_rootAgents.Add(avatar.UUID);
867 }
868 }
869 }
870
871 private void MakeChildAgent(ScenePresence avatar)
872 {
873 List<ScenePresence> presences = m_scene.GetAvatars();
874 int rootcount = 0;
875 for (int i = 0; i < presences.Count; i++)
876 {
877 if (presences[i] != null)
878 {
879 if (!presences[i].IsChildAgent)
880 rootcount++;
881 }
882 }
883 if (rootcount <= 1)
884 StopThread();
885
886 lock (m_rootAgents)
887 {
888 if (m_rootAgents.Contains(avatar.UUID))
889 {
890 m_rootAgents.Remove(avatar.UUID);
891 }
892 }
893 }
894 }
895
896 public struct MapRequestState
897 {
898 public UUID agentID;
899 public uint flags;
900 public uint EstateID;
901 public bool godlike;
902 public uint itemtype;
903 public ulong regionhandle;
904 }
905}