WorldMapModule.cs 64 KB

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