WorldMapModule.cs 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577
  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 OpenSimulator 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. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Drawing;
  31. using System.Drawing.Imaging;
  32. using System.IO;
  33. using System.Net;
  34. using System.Reflection;
  35. using System.Runtime.Remoting.Messaging;
  36. using System.Threading;
  37. using log4net;
  38. using Nini.Config;
  39. using OpenMetaverse;
  40. using OpenMetaverse.Imaging;
  41. using OpenMetaverse.StructuredData;
  42. using Mono.Addins;
  43. using OpenSim.Framework;
  44. using OpenSim.Framework.Capabilities;
  45. using OpenSim.Framework.Monitoring;
  46. using OpenSim.Framework.Servers;
  47. using OpenSim.Framework.Servers.HttpServer;
  48. using OpenSim.Region.Framework.Interfaces;
  49. using OpenSim.Region.Framework.Scenes;
  50. using OpenSim.Region.CoreModules.World.Land;
  51. using Caps=OpenSim.Framework.Capabilities.Caps;
  52. using OSDArray=OpenMetaverse.StructuredData.OSDArray;
  53. using OSDMap=OpenMetaverse.StructuredData.OSDMap;
  54. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  55. namespace OpenSim.Region.CoreModules.World.WorldMap
  56. {
  57. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")]
  58. public class WorldMapModule : INonSharedRegionModule, IWorldMapModule
  59. {
  60. private static readonly ILog m_log =
  61. LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  62. private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg";
  63. private static readonly UUID STOP_UUID = UUID.Random();
  64. private static readonly string m_mapLayerPath = "0001/";
  65. private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
  66. protected Scene m_scene;
  67. private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
  68. private int cachedTime = 0;
  69. private int blacklistTimeout = 10*60*1000; // 10 minutes
  70. private byte[] myMapImageJPEG;
  71. protected volatile 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 volatile bool threadrunning = false;
  78. private IServiceThrottleModule m_ServiceThrottle;
  79. //private int CacheRegionsDistance = 256;
  80. #region INonSharedRegionModule Members
  81. public virtual void Initialise (IConfigSource config)
  82. {
  83. string[] configSections = new string[] { "Map", "Startup" };
  84. if (Util.GetConfigVarFromSections<string>(
  85. config, "WorldMapModule", configSections, "WorldMap") == "WorldMap")
  86. m_Enabled = true;
  87. blacklistTimeout
  88. = Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000;
  89. }
  90. public virtual void AddRegion (Scene scene)
  91. {
  92. if (!m_Enabled)
  93. return;
  94. lock (scene)
  95. {
  96. m_scene = scene;
  97. m_scene.RegisterModuleInterface<IWorldMapModule>(this);
  98. m_scene.AddCommand(
  99. "Regions", this, "export-map",
  100. "export-map [<path>]",
  101. "Save an image of the world map", HandleExportWorldMapConsoleCommand);
  102. AddHandlers();
  103. }
  104. }
  105. public virtual void RemoveRegion (Scene scene)
  106. {
  107. if (!m_Enabled)
  108. return;
  109. lock (m_scene)
  110. {
  111. m_Enabled = false;
  112. RemoveHandlers();
  113. m_scene = null;
  114. }
  115. }
  116. public virtual void RegionLoaded (Scene scene)
  117. {
  118. if (!m_Enabled)
  119. return;
  120. m_ServiceThrottle = scene.RequestModuleInterface<IServiceThrottleModule>();
  121. }
  122. public virtual void Close()
  123. {
  124. }
  125. public Type ReplaceableInterface
  126. {
  127. get { return null; }
  128. }
  129. public virtual string Name
  130. {
  131. get { return "WorldMapModule"; }
  132. }
  133. #endregion
  134. // this has to be called with a lock on m_scene
  135. protected virtual void AddHandlers()
  136. {
  137. myMapImageJPEG = new byte[0];
  138. string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString();
  139. regionimage = regionimage.Replace("-", "");
  140. m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage);
  141. MainServer.Instance.AddHTTPHandler(regionimage,
  142. new GenericHTTPDOSProtector(OnHTTPGetMapImage, OnHTTPThrottled, new BasicDosProtectorOptions()
  143. {
  144. AllowXForwardedFor = false,
  145. ForgetTimeSpan = TimeSpan.FromMinutes(2),
  146. MaxRequestsInTimeframe = 4,
  147. ReportingName = "MAPDOSPROTECTOR",
  148. RequestTimeSpan = TimeSpan.FromSeconds(10),
  149. ThrottledAction = ThrottleAction.DoThrottledMethod
  150. }).Process);
  151. MainServer.Instance.AddLLSDHandler(
  152. "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
  153. m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
  154. m_scene.EventManager.OnNewClient += OnNewClient;
  155. m_scene.EventManager.OnClientClosed += ClientLoggedOut;
  156. m_scene.EventManager.OnMakeChildAgent += MakeChildAgent;
  157. m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
  158. m_scene.EventManager.OnRegionUp += OnRegionUp;
  159. // StartThread(new object());
  160. }
  161. // this has to be called with a lock on m_scene
  162. protected virtual void RemoveHandlers()
  163. {
  164. // StopThread();
  165. m_scene.EventManager.OnRegionUp -= OnRegionUp;
  166. m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent;
  167. m_scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
  168. m_scene.EventManager.OnClientClosed -= ClientLoggedOut;
  169. m_scene.EventManager.OnNewClient -= OnNewClient;
  170. m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
  171. string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString();
  172. regionimage = regionimage.Replace("-", "");
  173. MainServer.Instance.RemoveLLSDHandler("/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(),
  174. HandleRemoteMapItemRequest);
  175. MainServer.Instance.RemoveHTTPHandler("", regionimage);
  176. }
  177. public void OnRegisterCaps(UUID agentID, Caps caps)
  178. {
  179. //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
  180. string capsBase = "/CAPS/" + caps.CapsObjectPath;
  181. caps.RegisterHandler(
  182. "MapLayer",
  183. new RestStreamHandler(
  184. "POST",
  185. capsBase + m_mapLayerPath,
  186. (request, path, param, httpRequest, httpResponse)
  187. => MapLayerRequest(request, path, param, agentID, caps),
  188. "MapLayer",
  189. agentID.ToString()));
  190. }
  191. /// <summary>
  192. /// Callback for a map layer request
  193. /// </summary>
  194. /// <param name="request"></param>
  195. /// <param name="path"></param>
  196. /// <param name="param"></param>
  197. /// <param name="agentID"></param>
  198. /// <param name="caps"></param>
  199. /// <returns></returns>
  200. public string MapLayerRequest(string request, string path, string param,
  201. UUID agentID, Caps caps)
  202. {
  203. //try
  204. //
  205. //m_log.DebugFormat("[MAPLAYER]: path: {0}, param: {1}, agent:{2}",
  206. // path, param, agentID.ToString());
  207. // There is a major hack going on in this method. The viewer doesn't request
  208. // map blocks (RequestMapBlocks) above 2048. That means that if we don't hack,
  209. // grids above that cell don't have a map at all. So, here's the hack: we wait
  210. // for this CAP request to come, and we inject the map blocks at this point.
  211. // In a normal scenario, this request simply sends back the MapLayer (the blue color).
  212. // In the hacked scenario, it also sends the map blocks via UDP.
  213. //
  214. // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is
  215. // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks.
  216. if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048)
  217. {
  218. ScenePresence avatarPresence = null;
  219. m_scene.TryGetScenePresence(agentID, out avatarPresence);
  220. if (avatarPresence != null)
  221. {
  222. bool lookup = false;
  223. lock (cachedMapBlocks)
  224. {
  225. if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch()))
  226. {
  227. List<MapBlockData> mapBlocks;
  228. mapBlocks = cachedMapBlocks;
  229. avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
  230. }
  231. else
  232. {
  233. lookup = true;
  234. }
  235. }
  236. if (lookup)
  237. {
  238. List<MapBlockData> mapBlocks = new List<MapBlockData>(); ;
  239. List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
  240. (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize,
  241. (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize,
  242. (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize,
  243. (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize);
  244. foreach (GridRegion r in regions)
  245. {
  246. MapBlockData block = new MapBlockData();
  247. MapBlockFromGridRegion(block, r, 0);
  248. mapBlocks.Add(block);
  249. }
  250. avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
  251. lock (cachedMapBlocks)
  252. cachedMapBlocks = mapBlocks;
  253. cachedTime = Util.UnixTimeSinceEpoch();
  254. }
  255. }
  256. }
  257. LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
  258. mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
  259. return mapResponse.ToString();
  260. }
  261. /// <summary>
  262. ///
  263. /// </summary>
  264. /// <param name="mapReq"></param>
  265. /// <returns></returns>
  266. public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
  267. {
  268. // m_log.DebugFormat("[WORLD MAP]: MapLayer Request in region: {0}", m_scene.RegionInfo.RegionName);
  269. LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
  270. mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
  271. return mapResponse;
  272. }
  273. /// <summary>
  274. ///
  275. /// </summary>
  276. /// <returns></returns>
  277. protected static OSDMapLayer GetOSDMapLayerResponse()
  278. {
  279. OSDMapLayer mapLayer = new OSDMapLayer();
  280. mapLayer.Right = 5000;
  281. mapLayer.Top = 5000;
  282. mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
  283. return mapLayer;
  284. }
  285. #region EventHandlers
  286. /// <summary>
  287. /// Registered for event
  288. /// </summary>
  289. /// <param name="client"></param>
  290. private void OnNewClient(IClientAPI client)
  291. {
  292. client.OnRequestMapBlocks += RequestMapBlocks;
  293. client.OnMapItemRequest += HandleMapItemRequest;
  294. }
  295. /// <summary>
  296. /// Client logged out, check to see if there are any more root agents in the simulator
  297. /// If not, stop the mapItemRequest Thread
  298. /// Event handler
  299. /// </summary>
  300. /// <param name="AgentId">AgentID that logged out</param>
  301. private void ClientLoggedOut(UUID AgentId, Scene scene)
  302. {
  303. lock (m_rootAgents)
  304. {
  305. m_rootAgents.Remove(AgentId);
  306. }
  307. }
  308. #endregion
  309. /// <summary>
  310. /// Starts the MapItemRequest Thread
  311. /// Note that this only gets started when there are actually agents in the region
  312. /// Additionally, it gets stopped when there are none.
  313. /// </summary>
  314. /// <param name="o"></param>
  315. private void StartThread(object o)
  316. {
  317. if (threadrunning) return;
  318. threadrunning = true;
  319. // m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread");
  320. Watchdog.StartThread(
  321. process,
  322. string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName),
  323. ThreadPriority.BelowNormal,
  324. true,
  325. true);
  326. }
  327. /// <summary>
  328. /// Enqueues a 'stop thread' MapRequestState. Causes the MapItemRequest thread to end
  329. /// </summary>
  330. private void StopThread()
  331. {
  332. MapRequestState st = new MapRequestState();
  333. st.agentID = STOP_UUID;
  334. st.EstateID=0;
  335. st.flags=0;
  336. st.godlike=false;
  337. st.itemtype=0;
  338. st.regionhandle=0;
  339. requests.Enqueue(st);
  340. }
  341. public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
  342. uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
  343. {
  344. // m_log.DebugFormat("[WORLD MAP]: Handle MapItem request {0} {1}", regionhandle, itemtype);
  345. lock (m_rootAgents)
  346. {
  347. if (!m_rootAgents.Contains(remoteClient.AgentId))
  348. return;
  349. }
  350. uint xstart = 0;
  351. uint ystart = 0;
  352. Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
  353. if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots)
  354. {
  355. if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
  356. {
  357. // Local Map Item Request
  358. int tc = Environment.TickCount;
  359. List<mapItemReply> mapitems = new List<mapItemReply>();
  360. mapItemReply mapitem = new mapItemReply();
  361. if (m_scene.GetRootAgentCount() <= 1)
  362. {
  363. mapitem = new mapItemReply();
  364. mapitem.x = (uint)(xstart + 1);
  365. mapitem.y = (uint)(ystart + 1);
  366. mapitem.id = UUID.Zero;
  367. mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
  368. mapitem.Extra = 0;
  369. mapitem.Extra2 = 0;
  370. mapitems.Add(mapitem);
  371. }
  372. else
  373. {
  374. m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
  375. {
  376. // Don't send a green dot for yourself
  377. if (sp.UUID != remoteClient.AgentId)
  378. {
  379. mapitem = new mapItemReply();
  380. mapitem.x = (uint)(xstart + sp.AbsolutePosition.X);
  381. mapitem.y = (uint)(ystart + sp.AbsolutePosition.Y);
  382. mapitem.id = UUID.Zero;
  383. mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
  384. mapitem.Extra = 1;
  385. mapitem.Extra2 = 0;
  386. mapitems.Add(mapitem);
  387. }
  388. });
  389. }
  390. remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
  391. }
  392. else
  393. {
  394. // Remote Map Item Request
  395. // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes.
  396. RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
  397. }
  398. }
  399. else if (itemtype == 7) // Service 7 (MAP_ITEM_LAND_FOR_SALE)
  400. {
  401. if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
  402. {
  403. // Parcels
  404. ILandChannel landChannel = m_scene.LandChannel;
  405. List<ILandObject> parcels = landChannel.AllParcels();
  406. // Local Map Item Request
  407. List<mapItemReply> mapitems = new List<mapItemReply>();
  408. mapItemReply mapitem = new mapItemReply();
  409. if ((parcels != null) && (parcels.Count >= 1))
  410. {
  411. foreach (ILandObject parcel_interface in parcels)
  412. {
  413. // Play it safe
  414. if (!(parcel_interface is LandObject))
  415. continue;
  416. LandObject land = (LandObject)parcel_interface;
  417. LandData parcel = land.LandData;
  418. // Show land for sale
  419. if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
  420. {
  421. Vector3 min = parcel.AABBMin;
  422. Vector3 max = parcel.AABBMax;
  423. float x = (min.X+max.X)/2;
  424. float y = (min.Y+max.Y)/2;
  425. mapitem = new mapItemReply();
  426. mapitem.x = (uint)(xstart + x);
  427. mapitem.y = (uint)(ystart + y);
  428. // mapitem.z = (uint)m_scene.GetGroundHeight(x,y);
  429. mapitem.id = parcel.GlobalID;
  430. mapitem.name = parcel.Name;
  431. mapitem.Extra = parcel.Area;
  432. mapitem.Extra2 = parcel.SalePrice;
  433. mapitems.Add(mapitem);
  434. }
  435. }
  436. }
  437. remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
  438. }
  439. else
  440. {
  441. // Remote Map Item Request
  442. // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes.
  443. RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
  444. }
  445. }
  446. else if (itemtype == 1) // Service 1 (MAP_ITEM_TELEHUB)
  447. {
  448. if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
  449. {
  450. List<mapItemReply> mapitems = new List<mapItemReply>();
  451. mapItemReply mapitem = new mapItemReply();
  452. SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
  453. if (sog != null)
  454. {
  455. mapitem = new mapItemReply();
  456. mapitem.x = (uint)(xstart + sog.AbsolutePosition.X);
  457. mapitem.y = (uint)(ystart + sog.AbsolutePosition.Y);
  458. mapitem.id = UUID.Zero;
  459. mapitem.name = sog.Name;
  460. mapitem.Extra = 0; // color (not used)
  461. mapitem.Extra2 = 0; // 0 = telehub / 1 = infohub
  462. mapitems.Add(mapitem);
  463. remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
  464. }
  465. }
  466. else
  467. {
  468. // Remote Map Item Request
  469. RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
  470. }
  471. }
  472. }
  473. private int nAsyncRequests = 0;
  474. /// <summary>
  475. /// Processing thread main() loop for doing remote mapitem requests
  476. /// </summary>
  477. public void process()
  478. {
  479. //const int MAX_ASYNC_REQUESTS = 20;
  480. try
  481. {
  482. while (true)
  483. {
  484. MapRequestState st = requests.Dequeue(1000);
  485. // end gracefully
  486. if (st.agentID == STOP_UUID)
  487. break;
  488. if (st.agentID != UUID.Zero)
  489. {
  490. bool dorequest = true;
  491. lock (m_rootAgents)
  492. {
  493. if (!m_rootAgents.Contains(st.agentID))
  494. dorequest = false;
  495. }
  496. if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle))
  497. {
  498. while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
  499. Thread.Sleep(80);
  500. RequestMapItemsDelegate d = RequestMapItemsAsync;
  501. d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null);
  502. //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
  503. //RequestMapItemsCompleted(response);
  504. Interlocked.Increment(ref nAsyncRequests);
  505. }
  506. }
  507. Watchdog.UpdateThread();
  508. }
  509. }
  510. catch (Exception e)
  511. {
  512. m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e);
  513. }
  514. threadrunning = false;
  515. Watchdog.RemoveThread();
  516. }
  517. const int MAX_ASYNC_REQUESTS = 20;
  518. /// <summary>
  519. /// Enqueues the map item request into the services throttle processing thread
  520. /// </summary>
  521. /// <param name="state"></param>
  522. public void EnqueueMapItemRequest(MapRequestState st)
  523. {
  524. m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate
  525. {
  526. if (st.agentID != UUID.Zero)
  527. {
  528. bool dorequest = true;
  529. lock (m_rootAgents)
  530. {
  531. if (!m_rootAgents.Contains(st.agentID))
  532. dorequest = false;
  533. }
  534. if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle))
  535. {
  536. if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
  537. {
  538. // AH!!! Recursive !
  539. // Put this request back in the queue and return
  540. EnqueueMapItemRequest(st);
  541. return;
  542. }
  543. RequestMapItemsDelegate d = RequestMapItemsAsync;
  544. d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null);
  545. //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
  546. //RequestMapItemsCompleted(response);
  547. Interlocked.Increment(ref nAsyncRequests);
  548. }
  549. }
  550. });
  551. }
  552. /// <summary>
  553. /// Sends the mapitem response to the IClientAPI
  554. /// </summary>
  555. /// <param name="response">The OSDMap Response for the mapitem</param>
  556. private void RequestMapItemsCompleted(IAsyncResult iar)
  557. {
  558. AsyncResult result = (AsyncResult)iar;
  559. RequestMapItemsDelegate icon = (RequestMapItemsDelegate)result.AsyncDelegate;
  560. OSDMap response = (OSDMap)icon.EndInvoke(iar);
  561. Interlocked.Decrement(ref nAsyncRequests);
  562. if (!response.ContainsKey("requestID"))
  563. return;
  564. UUID requestID = response["requestID"].AsUUID();
  565. if (requestID != UUID.Zero)
  566. {
  567. MapRequestState mrs = new MapRequestState();
  568. mrs.agentID = UUID.Zero;
  569. lock (m_openRequests)
  570. {
  571. if (m_openRequests.ContainsKey(requestID))
  572. {
  573. mrs = m_openRequests[requestID];
  574. m_openRequests.Remove(requestID);
  575. }
  576. }
  577. if (mrs.agentID != UUID.Zero)
  578. {
  579. ScenePresence av = null;
  580. m_scene.TryGetScenePresence(mrs.agentID, out av);
  581. if (av != null)
  582. {
  583. if (response.ContainsKey(mrs.itemtype.ToString()))
  584. {
  585. List<mapItemReply> returnitems = new List<mapItemReply>();
  586. OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()];
  587. for (int i = 0; i < itemarray.Count; i++)
  588. {
  589. OSDMap mapitem = (OSDMap)itemarray[i];
  590. mapItemReply mi = new mapItemReply();
  591. mi.x = (uint)mapitem["X"].AsInteger();
  592. mi.y = (uint)mapitem["Y"].AsInteger();
  593. mi.id = mapitem["ID"].AsUUID();
  594. mi.Extra = mapitem["Extra"].AsInteger();
  595. mi.Extra2 = mapitem["Extra2"].AsInteger();
  596. mi.name = mapitem["Name"].AsString();
  597. returnitems.Add(mi);
  598. }
  599. av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
  600. }
  601. // Service 7 (MAP_ITEM_LAND_FOR_SALE)
  602. uint itemtype = 7;
  603. if (response.ContainsKey(itemtype.ToString()))
  604. {
  605. List<mapItemReply> returnitems = new List<mapItemReply>();
  606. OSDArray itemarray = (OSDArray)response[itemtype.ToString()];
  607. for (int i = 0; i < itemarray.Count; i++)
  608. {
  609. OSDMap mapitem = (OSDMap)itemarray[i];
  610. mapItemReply mi = new mapItemReply();
  611. mi.x = (uint)mapitem["X"].AsInteger();
  612. mi.y = (uint)mapitem["Y"].AsInteger();
  613. mi.id = mapitem["ID"].AsUUID();
  614. mi.Extra = mapitem["Extra"].AsInteger();
  615. mi.Extra2 = mapitem["Extra2"].AsInteger();
  616. mi.name = mapitem["Name"].AsString();
  617. returnitems.Add(mi);
  618. }
  619. av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
  620. }
  621. // Service 1 (MAP_ITEM_TELEHUB)
  622. itemtype = 1;
  623. if (response.ContainsKey(itemtype.ToString()))
  624. {
  625. List<mapItemReply> returnitems = new List<mapItemReply>();
  626. OSDArray itemarray = (OSDArray)response[itemtype.ToString()];
  627. for (int i = 0; i < itemarray.Count; i++)
  628. {
  629. OSDMap mapitem = (OSDMap)itemarray[i];
  630. mapItemReply mi = new mapItemReply();
  631. mi.x = (uint)mapitem["X"].AsInteger();
  632. mi.y = (uint)mapitem["Y"].AsInteger();
  633. mi.id = mapitem["ID"].AsUUID();
  634. mi.Extra = mapitem["Extra"].AsInteger();
  635. mi.Extra2 = mapitem["Extra2"].AsInteger();
  636. mi.name = mapitem["Name"].AsString();
  637. returnitems.Add(mi);
  638. }
  639. av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
  640. }
  641. }
  642. }
  643. }
  644. }
  645. /// <summary>
  646. /// Enqueue the MapItem request for remote processing
  647. /// </summary>
  648. /// <param name="httpserver">blank string, we discover this in the process</param>
  649. /// <param name="id">Agent ID that we are making this request on behalf</param>
  650. /// <param name="flags">passed in from packet</param>
  651. /// <param name="EstateID">passed in from packet</param>
  652. /// <param name="godlike">passed in from packet</param>
  653. /// <param name="itemtype">passed in from packet</param>
  654. /// <param name="regionhandle">Region we're looking up</param>
  655. public void RequestMapItems(string httpserver, UUID id, uint flags,
  656. uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
  657. {
  658. MapRequestState st = new MapRequestState();
  659. st.agentID = id;
  660. st.flags = flags;
  661. st.EstateID = EstateID;
  662. st.godlike = godlike;
  663. st.itemtype = itemtype;
  664. st.regionhandle = regionhandle;
  665. EnqueueMapItemRequest(st);
  666. }
  667. private delegate OSDMap RequestMapItemsDelegate(UUID id, uint flags,
  668. uint EstateID, bool godlike, uint itemtype, ulong regionhandle);
  669. /// <summary>
  670. /// Does the actual remote mapitem request
  671. /// This should be called from an asynchronous thread
  672. /// Request failures get blacklisted until region restart so we don't
  673. /// continue to spend resources trying to contact regions that are down.
  674. /// </summary>
  675. /// <param name="httpserver">blank string, we discover this in the process</param>
  676. /// <param name="id">Agent ID that we are making this request on behalf</param>
  677. /// <param name="flags">passed in from packet</param>
  678. /// <param name="EstateID">passed in from packet</param>
  679. /// <param name="godlike">passed in from packet</param>
  680. /// <param name="itemtype">passed in from packet</param>
  681. /// <param name="regionhandle">Region we're looking up</param>
  682. /// <returns></returns>
  683. private OSDMap RequestMapItemsAsync(UUID id, uint flags,
  684. uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
  685. {
  686. // m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype);
  687. string httpserver = "";
  688. bool blacklisted = false;
  689. lock (m_blacklistedregions)
  690. {
  691. if (m_blacklistedregions.ContainsKey(regionhandle))
  692. {
  693. if (Environment.TickCount > (m_blacklistedregions[regionhandle] + blacklistTimeout))
  694. {
  695. m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted region {0}", regionhandle);
  696. m_blacklistedregions.Remove(regionhandle);
  697. }
  698. else
  699. blacklisted = true;
  700. }
  701. }
  702. if (blacklisted)
  703. return new OSDMap();
  704. UUID requestID = UUID.Random();
  705. lock (m_cachedRegionMapItemsAddress)
  706. {
  707. if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
  708. httpserver = m_cachedRegionMapItemsAddress[regionhandle];
  709. }
  710. if (httpserver.Length == 0)
  711. {
  712. uint x = 0, y = 0;
  713. Utils.LongToUInts(regionhandle, out x, out y);
  714. GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
  715. if (mreg != null)
  716. {
  717. httpserver = mreg.ServerURI + "MAP/MapItems/" + regionhandle.ToString();
  718. lock (m_cachedRegionMapItemsAddress)
  719. {
  720. if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
  721. m_cachedRegionMapItemsAddress.Add(regionhandle, httpserver);
  722. }
  723. }
  724. else
  725. {
  726. lock (m_blacklistedregions)
  727. {
  728. if (!m_blacklistedregions.ContainsKey(regionhandle))
  729. m_blacklistedregions.Add(regionhandle, Environment.TickCount);
  730. }
  731. //m_log.InfoFormat("[WORLD MAP]: Blacklisted region {0}", regionhandle.ToString());
  732. }
  733. }
  734. blacklisted = false;
  735. lock (m_blacklistedurls)
  736. {
  737. if (m_blacklistedurls.ContainsKey(httpserver))
  738. {
  739. if (Environment.TickCount > (m_blacklistedurls[httpserver] + blacklistTimeout))
  740. {
  741. m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted URL {0}", httpserver);
  742. m_blacklistedurls.Remove(httpserver);
  743. }
  744. else
  745. blacklisted = true;
  746. }
  747. }
  748. // Can't find the http server
  749. if (httpserver.Length == 0 || blacklisted)
  750. return new OSDMap();
  751. MapRequestState mrs = new MapRequestState();
  752. mrs.agentID = id;
  753. mrs.EstateID = EstateID;
  754. mrs.flags = flags;
  755. mrs.godlike = godlike;
  756. mrs.itemtype=itemtype;
  757. mrs.regionhandle = regionhandle;
  758. lock (m_openRequests)
  759. m_openRequests.Add(requestID, mrs);
  760. WebRequest mapitemsrequest = null;
  761. try
  762. {
  763. mapitemsrequest = WebRequest.Create(httpserver);
  764. }
  765. catch (Exception e)
  766. {
  767. m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e);
  768. return new OSDMap();
  769. }
  770. mapitemsrequest.Method = "POST";
  771. mapitemsrequest.ContentType = "application/xml+llsd";
  772. OSDMap RAMap = new OSDMap();
  773. // string RAMapString = RAMap.ToString();
  774. OSD LLSDofRAMap = RAMap; // RENAME if this works
  775. byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap);
  776. OSDMap responseMap = new OSDMap();
  777. responseMap["requestID"] = OSD.FromUUID(requestID);
  778. Stream os = null;
  779. try
  780. { // send the Post
  781. mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send
  782. os = mapitemsrequest.GetRequestStream();
  783. os.Write(buffer, 0, buffer.Length); //Send it
  784. //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from {0}", httpserver);
  785. }
  786. catch (WebException ex)
  787. {
  788. m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
  789. responseMap["connect"] = OSD.FromBoolean(false);
  790. lock (m_blacklistedurls)
  791. {
  792. if (!m_blacklistedurls.ContainsKey(httpserver))
  793. m_blacklistedurls.Add(httpserver, Environment.TickCount);
  794. }
  795. m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
  796. return responseMap;
  797. }
  798. catch
  799. {
  800. m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
  801. responseMap["connect"] = OSD.FromBoolean(false);
  802. return responseMap;
  803. }
  804. finally
  805. {
  806. if (os != null)
  807. os.Close();
  808. }
  809. string response_mapItems_reply = null;
  810. {
  811. try
  812. {
  813. using (WebResponse webResponse = mapitemsrequest.GetResponse())
  814. {
  815. if (webResponse != null)
  816. {
  817. using (Stream s = webResponse.GetResponseStream())
  818. using (StreamReader sr = new StreamReader(s))
  819. response_mapItems_reply = sr.ReadToEnd().Trim();
  820. }
  821. else
  822. {
  823. return new OSDMap();
  824. }
  825. }
  826. }
  827. catch (WebException)
  828. {
  829. responseMap["connect"] = OSD.FromBoolean(false);
  830. lock (m_blacklistedurls)
  831. {
  832. if (!m_blacklistedurls.ContainsKey(httpserver))
  833. m_blacklistedurls.Add(httpserver, Environment.TickCount);
  834. }
  835. m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
  836. return responseMap;
  837. }
  838. catch
  839. {
  840. m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
  841. responseMap["connect"] = OSD.FromBoolean(false);
  842. lock (m_blacklistedregions)
  843. {
  844. if (!m_blacklistedregions.ContainsKey(regionhandle))
  845. m_blacklistedregions.Add(regionhandle, Environment.TickCount);
  846. }
  847. return responseMap;
  848. }
  849. OSD rezResponse = null;
  850. try
  851. {
  852. rezResponse = OSDParser.DeserializeLLSDXml(response_mapItems_reply);
  853. responseMap = (OSDMap)rezResponse;
  854. responseMap["requestID"] = OSD.FromUUID(requestID);
  855. }
  856. catch (Exception ex)
  857. {
  858. m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message);
  859. responseMap["connect"] = OSD.FromBoolean(false);
  860. lock (m_blacklistedregions)
  861. {
  862. if (!m_blacklistedregions.ContainsKey(regionhandle))
  863. m_blacklistedregions.Add(regionhandle, Environment.TickCount);
  864. }
  865. return responseMap;
  866. }
  867. }
  868. if (!responseMap.ContainsKey(itemtype.ToString())) // remote sim doesnt have the stated region handle
  869. {
  870. m_log.DebugFormat("[WORLD MAP]: Remote sim does not have the stated region. Blacklisting.");
  871. lock (m_blacklistedregions)
  872. {
  873. if (!m_blacklistedregions.ContainsKey(regionhandle))
  874. m_blacklistedregions.Add(regionhandle, Environment.TickCount);
  875. }
  876. }
  877. return responseMap;
  878. }
  879. /// <summary>
  880. /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates
  881. /// </summary>
  882. /// <param name="minX"></param>
  883. /// <param name="minY"></param>
  884. /// <param name="maxX"></param>
  885. /// <param name="maxY"></param>
  886. public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
  887. {
  888. //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
  889. if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
  890. {
  891. List<MapBlockData> response = new List<MapBlockData>();
  892. // this should return one mapblock at most. It is triggered by a click
  893. // on an unloaded square.
  894. // But make sure: Look whether the one we requested is in there
  895. List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
  896. minX * (int)Constants.RegionSize,
  897. maxX * (int)Constants.RegionSize,
  898. minY * (int)Constants.RegionSize,
  899. maxY * (int)Constants.RegionSize);
  900. if (regions != null)
  901. {
  902. foreach (GridRegion r in regions)
  903. {
  904. if ((r.RegionLocX == minX * (int)Constants.RegionSize) &&
  905. (r.RegionLocY == minY * (int)Constants.RegionSize))
  906. {
  907. // found it => add it to response
  908. MapBlockData block = new MapBlockData();
  909. MapBlockFromGridRegion(block, r, flag);
  910. response.Add(block);
  911. break;
  912. }
  913. }
  914. }
  915. if (response.Count == 0)
  916. {
  917. // response still empty => couldn't find the map-tile the user clicked on => tell the client
  918. MapBlockData block = new MapBlockData();
  919. block.X = (ushort)minX;
  920. block.Y = (ushort)minY;
  921. block.Access = 254; // means 'simulator is offline'
  922. response.Add(block);
  923. }
  924. // The lower 16 bits are an unsigned int16
  925. remoteClient.SendMapBlock(response, flag & 0xffff);
  926. }
  927. else
  928. {
  929. // normal mapblock request. Use the provided values
  930. GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag);
  931. }
  932. }
  933. protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
  934. {
  935. List<MapBlockData> mapBlocks = new List<MapBlockData>();
  936. List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
  937. (minX - 4) * (int)Constants.RegionSize,
  938. (maxX + 4) * (int)Constants.RegionSize,
  939. (minY - 4) * (int)Constants.RegionSize,
  940. (maxY + 4) * (int)Constants.RegionSize);
  941. foreach (GridRegion r in regions)
  942. {
  943. MapBlockData block = new MapBlockData();
  944. MapBlockFromGridRegion(block, r, flag);
  945. mapBlocks.Add(block);
  946. }
  947. remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
  948. return mapBlocks;
  949. }
  950. protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag)
  951. {
  952. block.Access = r.Access;
  953. switch (flag & 0xffff)
  954. {
  955. case 0:
  956. block.MapImageId = r.TerrainImage;
  957. break;
  958. case 2:
  959. block.MapImageId = r.ParcelImage;
  960. break;
  961. default:
  962. block.MapImageId = UUID.Zero;
  963. break;
  964. }
  965. block.Name = r.RegionName;
  966. block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
  967. block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
  968. }
  969. public Hashtable OnHTTPThrottled(Hashtable keysvals)
  970. {
  971. Hashtable reply = new Hashtable();
  972. int statuscode = 500;
  973. reply["str_response_string"] = "I blocked you! HAHAHAHAHAHAHHAHAH";
  974. reply["int_response_code"] = statuscode;
  975. reply["content_type"] = "text/plain";
  976. return reply;
  977. }
  978. public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
  979. {
  980. m_log.Debug("[WORLD MAP]: Sending map image jpeg");
  981. Hashtable reply = new Hashtable();
  982. int statuscode = 200;
  983. byte[] jpeg = new byte[0];
  984. if (myMapImageJPEG.Length == 0)
  985. {
  986. MemoryStream imgstream = new MemoryStream();
  987. Bitmap mapTexture = new Bitmap(1,1);
  988. ManagedImage managedImage;
  989. Image image = (Image)mapTexture;
  990. try
  991. {
  992. // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data
  993. imgstream = new MemoryStream();
  994. // non-async because we know we have the asset immediately.
  995. AssetBase mapasset = m_scene.AssetService.Get(m_scene.RegionInfo.RegionSettings.TerrainImageID.ToString());
  996. // Decode image to System.Drawing.Image
  997. if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image))
  998. {
  999. // Save to bitmap
  1000. mapTexture = new Bitmap(image);
  1001. EncoderParameters myEncoderParameters = new EncoderParameters();
  1002. myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L);
  1003. // Save bitmap to stream
  1004. mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters);
  1005. // Write the stream to a byte array for output
  1006. jpeg = imgstream.ToArray();
  1007. myMapImageJPEG = jpeg;
  1008. }
  1009. }
  1010. catch (Exception)
  1011. {
  1012. // Dummy!
  1013. m_log.Warn("[WORLD MAP]: Unable to generate Map image");
  1014. }
  1015. finally
  1016. {
  1017. // Reclaim memory, these are unmanaged resources
  1018. // If we encountered an exception, one or more of these will be null
  1019. if (mapTexture != null)
  1020. mapTexture.Dispose();
  1021. if (image != null)
  1022. image.Dispose();
  1023. if (imgstream != null)
  1024. {
  1025. imgstream.Close();
  1026. imgstream.Dispose();
  1027. }
  1028. }
  1029. }
  1030. else
  1031. {
  1032. // Use cached version so we don't have to loose our mind
  1033. jpeg = myMapImageJPEG;
  1034. }
  1035. reply["str_response_string"] = Convert.ToBase64String(jpeg);
  1036. reply["int_response_code"] = statuscode;
  1037. reply["content_type"] = "image/jpeg";
  1038. return reply;
  1039. }
  1040. // From msdn
  1041. private static ImageCodecInfo GetEncoderInfo(String mimeType)
  1042. {
  1043. ImageCodecInfo[] encoders;
  1044. encoders = ImageCodecInfo.GetImageEncoders();
  1045. for (int j = 0; j < encoders.Length; ++j)
  1046. {
  1047. if (encoders[j].MimeType == mimeType)
  1048. return encoders[j];
  1049. }
  1050. return null;
  1051. }
  1052. /// <summary>
  1053. /// Export the world map
  1054. /// </summary>
  1055. /// <param name="fileName"></param>
  1056. public void HandleExportWorldMapConsoleCommand(string module, string[] cmdparams)
  1057. {
  1058. if (m_scene.ConsoleScene() == null)
  1059. {
  1060. // FIXME: If console region is root then this will be printed by every module. Currently, there is no
  1061. // way to prevent this, short of making the entire module shared (which is complete overkill).
  1062. // One possibility is to return a bool to signal whether the module has completely handled the command
  1063. m_log.InfoFormat("[WORLD MAP]: Please change to a specific region in order to export its world map");
  1064. return;
  1065. }
  1066. if (m_scene.ConsoleScene() != m_scene)
  1067. return;
  1068. string exportPath;
  1069. if (cmdparams.Length > 1)
  1070. exportPath = cmdparams[1];
  1071. else
  1072. exportPath = DEFAULT_WORLD_MAP_EXPORT_PATH;
  1073. m_log.InfoFormat(
  1074. "[WORLD MAP]: Exporting world map for {0} to {1}", m_scene.RegionInfo.RegionName, exportPath);
  1075. List<MapBlockData> mapBlocks = new List<MapBlockData>();
  1076. List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
  1077. (int)(m_scene.RegionInfo.RegionLocX - 9) * (int)Constants.RegionSize,
  1078. (int)(m_scene.RegionInfo.RegionLocX + 9) * (int)Constants.RegionSize,
  1079. (int)(m_scene.RegionInfo.RegionLocY - 9) * (int)Constants.RegionSize,
  1080. (int)(m_scene.RegionInfo.RegionLocY + 9) * (int)Constants.RegionSize);
  1081. List<AssetBase> textures = new List<AssetBase>();
  1082. List<Image> bitImages = new List<Image>();
  1083. foreach (GridRegion r in regions)
  1084. {
  1085. MapBlockData mapBlock = new MapBlockData();
  1086. MapBlockFromGridRegion(mapBlock, r, 0);
  1087. AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
  1088. if (texAsset != null)
  1089. {
  1090. textures.Add(texAsset);
  1091. }
  1092. //else
  1093. //{
  1094. // // WHAT?!? This doesn't seem right. Commenting (diva)
  1095. // texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
  1096. // if (texAsset != null)
  1097. // {
  1098. // textures.Add(texAsset);
  1099. // }
  1100. //}
  1101. }
  1102. foreach (AssetBase asset in textures)
  1103. {
  1104. ManagedImage managedImage;
  1105. Image image;
  1106. if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
  1107. bitImages.Add(image);
  1108. }
  1109. Bitmap mapTexture = new Bitmap(2560, 2560);
  1110. Graphics g = Graphics.FromImage(mapTexture);
  1111. SolidBrush sea = new SolidBrush(Color.DarkBlue);
  1112. g.FillRectangle(sea, 0, 0, 2560, 2560);
  1113. for (int i = 0; i < mapBlocks.Count; i++)
  1114. {
  1115. ushort x = (ushort)((mapBlocks[i].X - m_scene.RegionInfo.RegionLocX) + 10);
  1116. ushort y = (ushort)((mapBlocks[i].Y - m_scene.RegionInfo.RegionLocY) + 10);
  1117. g.DrawImage(bitImages[i], (x * 128), 2560 - (y * 128), 128, 128); // y origin is top
  1118. }
  1119. mapTexture.Save(exportPath, ImageFormat.Jpeg);
  1120. m_log.InfoFormat(
  1121. "[WORLD MAP]: Successfully exported world map for {0} to {1}",
  1122. m_scene.RegionInfo.RegionName, exportPath);
  1123. }
  1124. public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
  1125. {
  1126. uint xstart = 0;
  1127. uint ystart = 0;
  1128. Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
  1129. // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots)
  1130. OSDMap responsemap = new OSDMap();
  1131. int tc = Environment.TickCount;
  1132. if (m_scene.GetRootAgentCount() == 0)
  1133. {
  1134. OSDMap responsemapdata = new OSDMap();
  1135. responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1));
  1136. responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1));
  1137. responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
  1138. responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
  1139. responsemapdata["Extra"] = OSD.FromInteger(0);
  1140. responsemapdata["Extra2"] = OSD.FromInteger(0);
  1141. OSDArray responsearr = new OSDArray();
  1142. responsearr.Add(responsemapdata);
  1143. responsemap["6"] = responsearr;
  1144. }
  1145. else
  1146. {
  1147. OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount());
  1148. m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
  1149. {
  1150. OSDMap responsemapdata = new OSDMap();
  1151. responsemapdata["X"] = OSD.FromInteger((int)(xstart + sp.AbsolutePosition.X));
  1152. responsemapdata["Y"] = OSD.FromInteger((int)(ystart + sp.AbsolutePosition.Y));
  1153. responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
  1154. responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
  1155. responsemapdata["Extra"] = OSD.FromInteger(1);
  1156. responsemapdata["Extra2"] = OSD.FromInteger(0);
  1157. responsearr.Add(responsemapdata);
  1158. });
  1159. responsemap["6"] = responsearr;
  1160. }
  1161. // Service 7 (MAP_ITEM_LAND_FOR_SALE)
  1162. ILandChannel landChannel = m_scene.LandChannel;
  1163. List<ILandObject> parcels = landChannel.AllParcels();
  1164. if ((parcels == null) || (parcels.Count == 0))
  1165. {
  1166. OSDMap responsemapdata = new OSDMap();
  1167. responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1));
  1168. responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1));
  1169. responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
  1170. responsemapdata["Name"] = OSD.FromString("");
  1171. responsemapdata["Extra"] = OSD.FromInteger(0);
  1172. responsemapdata["Extra2"] = OSD.FromInteger(0);
  1173. OSDArray responsearr = new OSDArray();
  1174. responsearr.Add(responsemapdata);
  1175. responsemap["7"] = responsearr;
  1176. }
  1177. else
  1178. {
  1179. OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount());
  1180. foreach (ILandObject parcel_interface in parcels)
  1181. {
  1182. // Play it safe
  1183. if (!(parcel_interface is LandObject))
  1184. continue;
  1185. LandObject land = (LandObject)parcel_interface;
  1186. LandData parcel = land.LandData;
  1187. // Show land for sale
  1188. if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
  1189. {
  1190. Vector3 min = parcel.AABBMin;
  1191. Vector3 max = parcel.AABBMax;
  1192. float x = (min.X+max.X)/2;
  1193. float y = (min.Y+max.Y)/2;
  1194. OSDMap responsemapdata = new OSDMap();
  1195. responsemapdata["X"] = OSD.FromInteger((int)(xstart + x));
  1196. responsemapdata["Y"] = OSD.FromInteger((int)(ystart + y));
  1197. // responsemapdata["Z"] = OSD.FromInteger((int)m_scene.GetGroundHeight(x,y));
  1198. responsemapdata["ID"] = OSD.FromUUID(parcel.GlobalID);
  1199. responsemapdata["Name"] = OSD.FromString(parcel.Name);
  1200. responsemapdata["Extra"] = OSD.FromInteger(parcel.Area);
  1201. responsemapdata["Extra2"] = OSD.FromInteger(parcel.SalePrice);
  1202. responsearr.Add(responsemapdata);
  1203. }
  1204. }
  1205. responsemap["7"] = responsearr;
  1206. }
  1207. if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
  1208. {
  1209. SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
  1210. if (sog != null)
  1211. {
  1212. OSDArray responsearr = new OSDArray();
  1213. OSDMap responsemapdata = new OSDMap();
  1214. responsemapdata["X"] = OSD.FromInteger((int)(xstart + sog.AbsolutePosition.X));
  1215. responsemapdata["Y"] = OSD.FromInteger((int)(ystart + sog.AbsolutePosition.Y));
  1216. // responsemapdata["Z"] = OSD.FromInteger((int)m_scene.GetGroundHeight(x,y));
  1217. responsemapdata["ID"] = OSD.FromUUID(sog.UUID);
  1218. responsemapdata["Name"] = OSD.FromString(sog.Name);
  1219. responsemapdata["Extra"] = OSD.FromInteger(0); // color (unused)
  1220. responsemapdata["Extra2"] = OSD.FromInteger(0); // 0 = telehub / 1 = infohub
  1221. responsearr.Add(responsemapdata);
  1222. responsemap["1"] = responsearr;
  1223. }
  1224. }
  1225. return responsemap;
  1226. }
  1227. public void GenerateMaptile()
  1228. {
  1229. // Cannot create a map for a nonexistant heightmap
  1230. if (m_scene.Heightmap == null)
  1231. return;
  1232. //create a texture asset of the terrain
  1233. IMapImageGenerator terrain = m_scene.RequestModuleInterface<IMapImageGenerator>();
  1234. if (terrain == null)
  1235. return;
  1236. m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName);
  1237. byte[] data = terrain.WriteJpeg2000Image();
  1238. if (data == null)
  1239. return;
  1240. byte[] overlay = GenerateOverlay();
  1241. UUID terrainImageID = UUID.Random();
  1242. UUID parcelImageID = UUID.Zero;
  1243. AssetBase asset = new AssetBase(
  1244. terrainImageID,
  1245. "terrainImage_" + m_scene.RegionInfo.RegionID.ToString(),
  1246. (sbyte)AssetType.Texture,
  1247. m_scene.RegionInfo.RegionID.ToString());
  1248. asset.Data = data;
  1249. asset.Description = m_scene.RegionInfo.RegionName;
  1250. asset.Temporary = false;
  1251. asset.Flags = AssetFlags.Maptile;
  1252. // Store the new one
  1253. m_log.DebugFormat("[WORLD MAP]: Storing map tile {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName);
  1254. m_scene.AssetService.Store(asset);
  1255. if (overlay != null)
  1256. {
  1257. parcelImageID = UUID.Random();
  1258. AssetBase parcels = new AssetBase(
  1259. parcelImageID,
  1260. "parcelImage_" + m_scene.RegionInfo.RegionID.ToString(),
  1261. (sbyte)AssetType.Texture,
  1262. m_scene.RegionInfo.RegionID.ToString());
  1263. parcels.Data = overlay;
  1264. parcels.Description = m_scene.RegionInfo.RegionName;
  1265. parcels.Temporary = false;
  1266. parcels.Flags = AssetFlags.Maptile;
  1267. m_scene.AssetService.Store(parcels);
  1268. }
  1269. // Switch to the new one
  1270. UUID lastTerrainImageID = m_scene.RegionInfo.RegionSettings.TerrainImageID;
  1271. UUID lastParcelImageID = m_scene.RegionInfo.RegionSettings.ParcelImageID;
  1272. m_scene.RegionInfo.RegionSettings.TerrainImageID = terrainImageID;
  1273. m_scene.RegionInfo.RegionSettings.ParcelImageID = parcelImageID;
  1274. m_scene.RegionInfo.RegionSettings.Save();
  1275. // Delete the old one
  1276. // m_log.DebugFormat("[WORLDMAP]: Deleting old map tile {0}", lastTerrainImageID);
  1277. m_scene.AssetService.Delete(lastTerrainImageID.ToString());
  1278. if (lastParcelImageID != UUID.Zero)
  1279. m_scene.AssetService.Delete(lastParcelImageID.ToString());
  1280. }
  1281. private void MakeRootAgent(ScenePresence avatar)
  1282. {
  1283. lock (m_rootAgents)
  1284. {
  1285. if (!m_rootAgents.Contains(avatar.UUID))
  1286. {
  1287. m_rootAgents.Add(avatar.UUID);
  1288. }
  1289. }
  1290. }
  1291. private void MakeChildAgent(ScenePresence avatar)
  1292. {
  1293. lock (m_rootAgents)
  1294. {
  1295. m_rootAgents.Remove(avatar.UUID);
  1296. }
  1297. }
  1298. public void OnRegionUp(GridRegion otherRegion)
  1299. {
  1300. ulong regionhandle = otherRegion.RegionHandle;
  1301. string httpserver = otherRegion.ServerURI + "MAP/MapItems/" + regionhandle.ToString();
  1302. lock (m_blacklistedregions)
  1303. {
  1304. if (!m_blacklistedregions.ContainsKey(regionhandle))
  1305. m_blacklistedregions.Remove(regionhandle);
  1306. }
  1307. lock (m_blacklistedurls)
  1308. {
  1309. if (m_blacklistedurls.ContainsKey(httpserver))
  1310. m_blacklistedurls.Remove(httpserver);
  1311. }
  1312. lock (m_cachedRegionMapItemsAddress)
  1313. {
  1314. if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
  1315. m_cachedRegionMapItemsAddress.Remove(regionhandle);
  1316. }
  1317. }
  1318. private Byte[] GenerateOverlay()
  1319. {
  1320. Bitmap overlay = new Bitmap(256, 256);
  1321. bool[,] saleBitmap = new bool[64, 64];
  1322. for (int x = 0 ; x < 64 ; x++)
  1323. {
  1324. for (int y = 0 ; y < 64 ; y++)
  1325. saleBitmap[x, y] = false;
  1326. }
  1327. bool landForSale = false;
  1328. List<ILandObject> parcels = m_scene.LandChannel.AllParcels();
  1329. Color background = Color.FromArgb(0, 0, 0, 0);
  1330. SolidBrush transparent = new SolidBrush(background);
  1331. Graphics g = Graphics.FromImage(overlay);
  1332. g.FillRectangle(transparent, 0, 0, 256, 256);
  1333. SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9));
  1334. foreach (ILandObject land in parcels)
  1335. {
  1336. // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
  1337. if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
  1338. {
  1339. landForSale = true;
  1340. saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap());
  1341. }
  1342. }
  1343. if (!landForSale)
  1344. {
  1345. m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
  1346. return null;
  1347. }
  1348. m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
  1349. for (int x = 0 ; x < 64 ; x++)
  1350. {
  1351. for (int y = 0 ; y < 64 ; y++)
  1352. {
  1353. if (saleBitmap[x, y])
  1354. g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4);
  1355. }
  1356. }
  1357. try
  1358. {
  1359. return OpenJPEG.EncodeFromImage(overlay, true);
  1360. }
  1361. catch (Exception e)
  1362. {
  1363. m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
  1364. }
  1365. return null;
  1366. }
  1367. }
  1368. public struct MapRequestState
  1369. {
  1370. public UUID agentID;
  1371. public uint flags;
  1372. public uint EstateID;
  1373. public bool godlike;
  1374. public uint itemtype;
  1375. public ulong regionhandle;
  1376. }
  1377. }