29 using System.Collections;
30 using System.Collections.Generic;
32 using System.Drawing.Imaging;
35 using System.Reflection;
36 using System.Runtime.Remoting.Messaging;
37 using System.Threading;
41 using OpenMetaverse.Imaging;
42 using OpenMetaverse.StructuredData;
44 using OpenSim.Framework;
45 using OpenSim.Framework.Capabilities;
46 using OpenSim.Framework.Monitoring;
47 using OpenSim.Framework.Servers;
48 using OpenSim.Framework.Servers.HttpServer;
49 using OpenSim.Region.Framework.Interfaces;
50 using OpenSim.Region.Framework.Scenes;
51 using OpenSim.Region.CoreModules.World.Land;
59 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"WorldMapModule")]
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63 #pragma warning disable 414
64 private static string LogHeader =
"[WORLD MAP]";
65 #pragma warning restore 414
67 private static readonly
string DEFAULT_WORLD_MAP_EXPORT_PATH =
"exportmap.jpg";
68 private static readonly
UUID STOP_UUID = UUID.Random();
69 private static readonly
string m_mapLayerPath =
"0001/";
73 private ManualResetEvent m_mapBlockRequestEvent =
new ManualResetEvent(
false);
74 private Dictionary<UUID, Queue<MapBlockRequestData>> m_mapBlockRequests =
new Dictionary<UUID, Queue<MapBlockRequestData>>();
80 private List<MapBlockData> cachedMapBlocks =
new List<MapBlockData>();
81 private byte[] myMapImageJPEG;
82 protected volatile bool m_Enabled =
false;
83 private ExpiringCache<string, int> m_blacklistedurls =
new ExpiringCache<string, int>();
84 private ExpiringCache<ulong, int> m_blacklistedregions =
new ExpiringCache<ulong, int>();
85 private ExpiringCache<ulong, string> m_cachedRegionMapItemsAddress =
new ExpiringCache<ulong, string>();
86 private ExpiringCache<ulong, OSDMap> m_cachedRegionMapItemsResponses =
87 new ExpiringCache<ulong, OSDMap>();
88 private List<UUID> m_rootAgents =
new List<UUID>();
89 private volatile bool threadrunning =
false;
91 private double expireBlackListTime = 600.0;
93 private const double expireResponsesTime = 120.0;
96 #region INonSharedRegionModule Members
99 string[] configSections =
new string[] {
"Map",
"Startup" };
101 if (Util.GetConfigVarFromSections<
string>(
102 config,
"WorldMapModule", configSections,
"WorldMap") ==
"WorldMap")
105 expireBlackListTime = (double)Util.GetConfigVarFromSections<
int>(config,
"BlacklistTimeout", configSections, 10 * 60);
120 "Regions",
this,
"export-map",
121 "export-map [<path>]",
122 "Save an image of the world map", HandleExportWorldMapConsoleCommand);
125 "Regions",
this,
"generate map",
127 "Generates and stores a new maptile.", HandleGenerateMapConsoleCommand);
159 public Type ReplaceableInterface
164 public virtual string Name
166 get {
return "WorldMapModule"; }
174 myMapImageJPEG =
new byte[0];
176 string regionimage =
"regionImage" + m_scene.RegionInfo.RegionID.ToString();
177 regionimage = regionimage.Replace(
"-",
"");
178 m_log.Info(
"[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI +
"index.php?method=" + regionimage);
180 MainServer.Instance.AddHTTPHandler(regionimage,
183 AllowXForwardedFor =
false,
184 ForgetTimeSpan = TimeSpan.FromMinutes(2),
185 MaxRequestsInTimeframe = 4,
186 ReportingName =
"MAPDOSPROTECTOR",
187 RequestTimeSpan = TimeSpan.FromSeconds(10),
188 ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
190 MainServer.Instance.AddLLSDHandler(
191 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
193 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
194 m_scene.EventManager.OnNewClient += OnNewClient;
195 m_scene.EventManager.OnClientClosed += ClientLoggedOut;
196 m_scene.EventManager.OnMakeChildAgent += MakeChildAgent;
197 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
198 m_scene.EventManager.OnRegionUp += OnRegionUp;
200 StartThread(
new object());
208 m_scene.EventManager.OnRegionUp -= OnRegionUp;
209 m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent;
210 m_scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
211 m_scene.EventManager.OnClientClosed -= ClientLoggedOut;
212 m_scene.EventManager.OnNewClient -= OnNewClient;
213 m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
215 string regionimage =
"regionImage" + m_scene.RegionInfo.RegionID.ToString();
216 regionimage = regionimage.Replace(
"-",
"");
217 MainServer.Instance.RemoveLLSDHandler(
"/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(),
218 HandleRemoteMapItemRequest);
219 MainServer.Instance.RemoveHTTPHandler(
"", regionimage);
225 string capsBase =
"/CAPS/" + caps.CapsObjectPath;
226 caps.RegisterHandler(
230 capsBase + m_mapLayerPath,
231 (request, path, param, httpRequest, httpResponse)
232 => MapLayerRequest(request, path, param, agentID, caps),
234 agentID.ToString()));
247 UUID agentID,
Caps caps)
316 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
317 return mapResponse.ToString();
329 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
342 mapLayer.Right = 2048;
344 mapLayer.ImageID =
new UUID(
"00000000-0000-1111-9999-000000000006");
348 #region EventHandlers
357 client.OnMapItemRequest += HandleMapItemRequest;
366 private void ClientLoggedOut(UUID AgentId,
Scene scene)
370 m_rootAgents.Remove(AgentId);
372 lock (m_mapBlockRequestEvent)
374 if (m_mapBlockRequests.ContainsKey(AgentId))
375 m_mapBlockRequests.Remove(AgentId);
386 private void StartThread(
object o)
388 if (threadrunning)
return;
389 threadrunning =
true;
393 WorkManager.StartThread(
395 string.Format(
"MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName),
396 ThreadPriority.BelowNormal,
399 WorkManager.StartThread(
401 string.Format(
"MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName),
402 ThreadPriority.BelowNormal,
410 private void StopThread()
412 MapRequestState st =
new MapRequestState();
413 st.agentID = STOP_UUID;
420 requests.Enqueue(st);
422 MapBlockRequestData req =
new MapBlockRequestData();
431 lock (m_mapBlockRequestEvent)
433 m_mapBlockRequests[UUID.Zero] =
new Queue<MapBlockRequestData>();
434 m_mapBlockRequests[UUID.Zero].Enqueue(req);
435 m_mapBlockRequestEvent.Set();
440 uint EstateID,
bool godlike, uint itemtype, ulong regionhandle)
446 if (!m_rootAgents.Contains(remoteClient.
AgentId))
451 if (regionhandle != 0 && regionhandle != m_scene.RegionInfo.RegionHandle)
455 RequestMapItems(
"", remoteClient.
AgentId, flags, EstateID, godlike, itemtype, regionhandle);
461 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
465 List<mapItemReply> mapitems =
new List<mapItemReply>();
474 if (regionhandle == 0)
478 case (
int)GridItemType.AgentLocations:
481 int tc = Environment.TickCount;
482 if (m_scene.GetRootAgentCount() <= 1)
488 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
490 mapitems.Add(mapitem);
503 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
505 mapitems.Add(mapitem);
509 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
512 case (
int)GridItemType.Telehub:
515 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
526 mapitems.Add(mapitem);
527 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
531 case (
int)GridItemType.AdultLandForSale:
532 case (
int)GridItemType.LandForSale:
535 adultRegion = m_scene.RegionInfo.RegionSettings.Maturity == 2;
538 if (itemtype == (
int)GridItemType.LandForSale)
543 if (itemtype == (
int)GridItemType.AdultLandForSale)
549 List<ILandObject> parcels = landChannel.AllParcels();
551 if ((parcels != null) && (parcels.Count >= 1))
559 LandObject land = (LandObject)parcel_interface;
563 if ((parcel.
Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
565 Vector3 min = parcel.AABBMin;
566 Vector3 max = parcel.AABBMax;
567 float x = (min.X + max.X) / 2;
568 float y = (min.Y + max.Y) / 2;
577 mapitems.Add(mapitem);
581 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
584 case (uint)GridItemType.PgEvent:
585 case (uint)GridItemType.MatureEvent:
586 case (uint)GridItemType.AdultEvent:
587 case (uint)GridItemType.Classified:
588 case (uint)GridItemType.Popular:
595 m_log.DebugFormat(
"[WORLD MAP]: Unknown MapItem type {1}", itemtype);
605 int tc = Environment.TickCount;
606 if (m_scene.GetRootAgentCount() <= 1)
612 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
614 mapitems.Add(mapitem);
627 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
629 mapitems.Add(mapitem);
633 remoteClient.SendMapItemReply(mapitems.ToArray(), 6, flags);
638 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
642 xstart + (uint)sog.AbsolutePosition.X,
643 ystart + (uint)sog.AbsolutePosition.Y,
649 mapitems.Add(mapitem);
650 remoteClient.SendMapItemReply(mapitems.ToArray(), 1, flags);
657 if (m_scene.RegionInfo.RegionSettings.Maturity == 2)
662 List<ILandObject> parcels = landChannel.AllParcels();
664 if ((parcels != null) && (parcels.Count >= 1))
672 LandObject land = (LandObject)parcel_interface;
676 if ((parcel.
Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
678 Vector3 min = parcel.AABBMin;
679 Vector3 max = parcel.AABBMax;
680 float x = (min.X + max.X) / 2;
681 float y = (min.Y + max.Y) / 2;
690 mapitems.Add(mapitem);
693 if(mapitems.Count >0)
694 remoteClient.SendMapItemReply(mapitems.ToArray(), its, flags);
700 private int nAsyncRequests = 0;
706 const int MAX_ASYNC_REQUESTS = 20;
714 Watchdog.UpdateThread();
719 st = requests.Dequeue(4900);
730 m_scene.TryGetScenePresence(st.agentID, out av);
731 if (av == null || av.IsChildAgent || av.IsDeleted || av.IsInTransit)
738 bool dorequest =
true;
739 OSDMap responseMap = null;
742 lock (m_cachedRegionMapItemsResponses)
744 if (m_cachedRegionMapItemsResponses.Contains(st.
regionhandle))
746 m_cachedRegionMapItemsResponses.TryGetValue(st.regionhandle, out responseMap);
750 m_cachedRegionMapItemsResponses.Add(st.regionhandle, null, expireResponsesTime);
756 Interlocked.Increment(ref nAsyncRequests);
758 Util.FireAndForget(x =>
760 RequestMapItemsAsync(rst.agentID, rst.flags, rst.EstateID, rst.godlike, rst.itemtype, rst.regionhandle);
766 if (responseMap != null)
771 if (responseMap.ContainsKey(st.
itemtype.ToString()))
773 List<mapItemReply> returnitems =
new List<mapItemReply>();
775 for (
int i = 0; i < itemarray.Count; i++)
779 mi.x = (uint)mapitem[
"X"].AsInteger();
780 mi.y = (uint)mapitem[
"Y"].AsInteger();
781 mi.id = mapitem[
"ID"].AsUUID();
782 mi.Extra = mapitem[
"Extra"].AsInteger();
783 mi.Extra2 = mapitem[
"Extra2"].AsInteger();
784 mi.name = mapitem[
"Name"].AsString();
787 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), st.
itemtype, st.
flags & 0xffff);
794 requests.Enqueue(st);
795 if (requests.Count() < 3)
800 while (nAsyncRequests >= MAX_ASYNC_REQUESTS)
803 Watchdog.UpdateThread();
810 m_log.ErrorFormat(
"[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e);
813 threadrunning =
false;
814 Watchdog.RemoveThread();
828 uint EstateID,
bool godlike, uint itemtype, ulong regionhandle)
833 st.EstateID = EstateID;
834 st.godlike = godlike;
835 st.itemtype = itemtype;
836 st.regionhandle = regionhandle;
838 requests.Enqueue(st);
841 uint[] itemTypesForcedSend =
new uint[] { 6, 1, 7, 10 };
857 private void RequestMapItemsAsync(UUID
id, uint flags,
858 uint EstateID,
bool godlike, uint itemtype, ulong regionhandle)
862 string httpserver =
"";
863 bool blacklisted =
false;
865 lock (m_blacklistedregions)
866 blacklisted = m_blacklistedregions.Contains(regionhandle);
870 Interlocked.Decrement(ref nAsyncRequests);
874 UUID requestID = UUID.Random();
875 lock (m_cachedRegionMapItemsAddress)
876 m_cachedRegionMapItemsAddress.TryGetValue(regionhandle, out httpserver);
878 if (httpserver == null || httpserver.Length == 0)
881 Util.RegionHandleToWorldLoc(regionhandle, out x, out y);
883 GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (
int)y);
887 httpserver = mreg.ServerURI +
"MAP/MapItems/" + regionhandle.ToString();
888 lock (m_cachedRegionMapItemsAddress)
889 m_cachedRegionMapItemsAddress.AddOrUpdate(regionhandle, httpserver, 2.0 * expireBlackListTime);
893 lock (m_blacklistedurls)
895 if (httpserver == null || httpserver.Length == 0 || m_blacklistedurls.Contains(httpserver))
898 lock (m_blacklistedregions)
899 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
901 Interlocked.Decrement(ref nAsyncRequests);
906 WebRequest mapitemsrequest = null;
909 mapitemsrequest = WebRequest.Create(httpserver);
913 m_log.DebugFormat(
"[WORLD MAP]: Access to {0} failed with {1}", httpserver, e);
914 Interlocked.Decrement(ref nAsyncRequests);
918 mapitemsrequest.Method =
"POST";
919 mapitemsrequest.ContentType =
"application/xml+llsd";
923 OSD LLSDofRAMap = RAMap;
925 byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap);
931 mapitemsrequest.ContentLength = buffer.Length;
932 using (Stream os = mapitemsrequest.GetRequestStream())
933 os.Write(buffer, 0, buffer.Length);
936 catch (WebException ex)
938 m_log.WarnFormat(
"[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
939 m_log.WarnFormat(
"[WORLD MAP]: Blacklisted url {0}", httpserver);
940 lock (m_blacklistedurls)
941 m_blacklistedurls.AddOrUpdate(httpserver, 0, expireBlackListTime);
942 lock (m_blacklistedregions)
943 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
945 Interlocked.Decrement(ref nAsyncRequests);
950 m_log.DebugFormat(
"[WORLD MAP]: RequestMapItems failed for {0}", httpserver);
951 Interlocked.Decrement(ref nAsyncRequests);
955 string response_mapItems_reply = null;
959 using (WebResponse webResponse = mapitemsrequest.GetResponse())
961 if (webResponse != null)
963 using (StreamReader sr =
new StreamReader(webResponse.GetResponseStream()))
965 response_mapItems_reply = sr.ReadToEnd().Trim();
970 Interlocked.Decrement(ref nAsyncRequests);
977 lock (m_blacklistedurls)
978 m_blacklistedurls.AddOrUpdate(httpserver, 0, expireBlackListTime);
979 lock (m_blacklistedregions)
980 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
982 m_log.WarnFormat("[WORLD MAP]: Blacklisted url {0}
", httpserver);
984 Interlocked.Decrement(ref nAsyncRequests);
989 m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed
for {0}
", httpserver);
990 lock (m_blacklistedregions)
991 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
993 Interlocked.Decrement(ref nAsyncRequests);
999 responseMap = (OSDMap)OSDParser.DeserializeLLSDXml(response_mapItems_reply);
1001 catch (Exception ex)
1003 m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}
", httpserver, ex.Message);
1004 lock (m_blacklistedregions)
1005 m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime);
1007 Interlocked.Decrement(ref nAsyncRequests);
1012 // cache the response that may include other valid items
1013 lock (m_cachedRegionMapItemsResponses)
1014 m_cachedRegionMapItemsResponses.AddOrUpdate(regionhandle, responseMap, expireResponsesTime);
1018 if (id != UUID.Zero)
1020 ScenePresence av = null;
1021 m_scene.TryGetScenePresence(id, out av);
1022 if (av != null && !av.IsChildAgent && !av.IsDeleted && !av.IsInTransit)
1024 // send all the items or viewers will never ask for them, except green dots
1025 foreach (uint itfs in itemTypesForcedSend)
1027 if (responseMap.ContainsKey(itfs.ToString()))
1029 List<mapItemReply> returnitems = new List<mapItemReply>();
1030 // OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()];
1031 OSDArray itemarray = (OSDArray)responseMap[itfs.ToString()];
1032 for (int i = 0; i < itemarray.Count; i++)
1034 OSDMap mapitem = (OSDMap)itemarray[i];
1035 mapItemReply mi = new mapItemReply();
1036 mi.x = (uint)mapitem["X
"].AsInteger();
1037 mi.y = (uint)mapitem["Y
"].AsInteger();
1038 mi.id = mapitem["ID
"].AsUUID();
1039 mi.Extra = mapitem["Extra
"].AsInteger();
1040 mi.Extra2 = mapitem["Extra2
"].AsInteger();
1041 mi.name = mapitem["Name
"].AsString();
1042 returnitems.Add(mi);
1044 // av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags);
1045 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itfs, flags);
1051 Interlocked.Decrement(ref nAsyncRequests);
1061 public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
1063 m_log.DebugFormat("[WoldMapModule]
RequestMapBlocks {0}={1}={2}={3} {4}
", minX, minY, maxX, maxY, flag);
1065 GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag);
1068 protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
1070 MapBlockRequestData req = new MapBlockRequestData();
1072 req.client = remoteClient;
1079 lock (m_mapBlockRequestEvent)
1081 if (!m_mapBlockRequests.ContainsKey(remoteClient.AgentId))
1082 m_mapBlockRequests[remoteClient.AgentId] = new Queue<MapBlockRequestData>();
1083 m_mapBlockRequests[remoteClient.AgentId].Enqueue(req);
1084 m_mapBlockRequestEvent.Set();
1087 return new List<MapBlockData>();
1090 protected void MapBlockSendThread()
1094 List<MapBlockRequestData> thisRunData = new List<MapBlockRequestData>();
1096 m_mapBlockRequestEvent.WaitOne();
1097 lock (m_mapBlockRequestEvent)
1100 foreach (Queue<MapBlockRequestData> q in m_mapBlockRequests.Values)
1103 thisRunData.Add(q.Dequeue());
1109 m_mapBlockRequestEvent.Reset();
1112 foreach (MapBlockRequestData req in thisRunData)
1114 // Null client stops thread
1115 if (req.client == null)
1118 GetAndSendBlocksInternal(req.client, req.minX, req.minY, req.maxX, req.maxY, req.flags);
1125 protected virtual List<MapBlockData> GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
1127 List<MapBlockData> allBlocks = new List<MapBlockData>();
1128 List<MapBlockData> mapBlocks = new List<MapBlockData>();
1129 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1130 minX * (int)Constants.RegionSize,
1131 maxX * (int)Constants.RegionSize,
1132 minY * (int)Constants.RegionSize,
1133 maxY * (int)Constants.RegionSize);
1135 // only send a negative answer for a single region request
1136 // corresponding to a click on the map. Current viewers
1137 // keep displaying "loading..
" without this
1138 if (regions.Count == 0 && (flag & 0x10000) != 0 && minX == maxX && minY == maxY)
1140 MapBlockData block = new MapBlockData();
1141 block.X = (ushort)minX;
1142 block.Y = (ushort)minY;
1143 block.MapImageId = UUID.Zero;
1144 block.Access = (byte)SimAccess.NonExistent;
1145 allBlocks.Add(block);
1146 mapBlocks.Add(block);
1147 remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
1153 foreach (GridRegion r in regions)
1157 MapBlockData block = new MapBlockData();
1158 MapBlockFromGridRegion(block, r, flag);
1159 mapBlocks.Add(block);
1160 allBlocks.Add(block);
1162 if (mapBlocks.Count >= 10)
1164 remoteClient.SendMapBlock(mapBlocks, flag);
1169 if (mapBlocks.Count > 0)
1170 remoteClient.SendMapBlock(mapBlocks, flag);
1175 public void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag)
1179 // we should not get here ??
1180 // block.Access = (byte)SimAccess.Down; this is for a grid reply on r
1181 block.Access = (byte)SimAccess.NonExistent;
1182 block.MapImageId = UUID.Zero;
1186 block.Access = r.Access;
1190 block.MapImageId = r.TerrainImage;
1193 block.MapImageId = r.ParcelImage;
1196 block.MapImageId = UUID.Zero;
1199 block.Name = r.RegionName;
1200 block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
1201 block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
1202 block.SizeX = (ushort)r.RegionSizeX;
1203 block.SizeY = (ushort)r.RegionSizeY;
1207 public Hashtable OnHTTPThrottled(Hashtable keysvals)
1209 Hashtable reply = new Hashtable();
1210 int statuscode = 500;
1211 reply["str_response_string
"] = "";
1212 reply["int_response_code
"] = statuscode;
1213 reply["content_type
"] = "text/plain
";
1217 public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
1219 Hashtable reply = new Hashtable();
1220 int statuscode = 200;
1221 byte[] jpeg = new byte[0];
1223 if (m_scene.RegionInfo.RegionSettings.TerrainImageID != UUID.Zero)
1225 m_log.Debug("[WORLD MAP]: Sending map image jpeg
");
1227 if (myMapImageJPEG.Length == 0)
1229 MemoryStream imgstream = null;
1230 Bitmap mapTexture = new Bitmap(1, 1);
1231 ManagedImage managedImage;
1232 Image image = (Image)mapTexture;
1236 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data
1238 imgstream = new MemoryStream();
1240 // non-async because we know we have the asset immediately.
1241 AssetBase mapasset = m_scene.AssetService.Get(m_scene.RegionInfo.RegionSettings.TerrainImageID.ToString());
1243 // Decode image to System.Drawing.Image
1244 if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image))
1247 mapTexture = new Bitmap(image);
1249 EncoderParameters myEncoderParameters = new EncoderParameters();
1250 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L);
1252 // Save bitmap to stream
1253 mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg
"), myEncoderParameters);
1255 // Write the stream to a byte array for output
1256 jpeg = imgstream.ToArray();
1257 myMapImageJPEG = jpeg;
1263 m_log.Warn("[WORLD MAP]: Unable to generate Map image
");
1267 // Reclaim memory, these are unmanaged resources
1268 // If we encountered an exception, one or more of these will be null
1269 if (mapTexture != null)
1270 mapTexture.Dispose();
1275 if (imgstream != null)
1276 imgstream.Dispose();
1281 // Use cached version so we don't have to loose our mind
1282 jpeg = myMapImageJPEG;
1286 reply["str_response_string
"] = Convert.ToBase64String(jpeg);
1287 reply["int_response_code
"] = statuscode;
1288 reply["content_type
"] = "image/jpeg
";
1294 private static ImageCodecInfo GetEncoderInfo(String mimeType)
1296 ImageCodecInfo[] encoders;
1297 encoders = ImageCodecInfo.GetImageEncoders();
1298 for (int j = 0; j < encoders.Length; ++j)
1300 if (encoders[j].MimeType == mimeType)
1310 public void HandleExportWorldMapConsoleCommand(string module, string[] cmdparams)
1312 if (m_scene.ConsoleScene() == null)
1314 // FIXME: If console region is root then this will be printed by every module. Currently, there is no
1315 // way to prevent this, short of making the entire module shared (which is complete overkill).
1316 // One possibility is to return a bool to signal whether the module has completely handled the command
1317 m_log.InfoFormat("[WORLD MAP]: Please change to a specific region in order to export its world map
");
1321 if (m_scene.ConsoleScene() != m_scene)
1326 if (cmdparams.Length > 1)
1327 exportPath = cmdparams[1];
1329 exportPath = DEFAULT_WORLD_MAP_EXPORT_PATH;
1332 "[WORLD MAP]: Exporting world map
for {0} to {1}
", m_scene.RegionInfo.RegionName, exportPath);
1334 List<MapBlockData> mapBlocks = new List<MapBlockData>();
1335 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1336 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 9),
1337 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 9),
1338 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 9),
1339 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 9));
1340 List<AssetBase> textures = new List<AssetBase>();
1341 List<Image> bitImages = new List<Image>();
1343 foreach (GridRegion r in regions)
1345 MapBlockData mapBlock = new MapBlockData();
1346 MapBlockFromGridRegion(mapBlock, r, 0);
1347 AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
1349 if (texAsset != null)
1351 textures.Add(texAsset);
1355 foreach (AssetBase asset in textures)
1357 ManagedImage managedImage;
1360 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
1361 bitImages.Add(image);
1364 Bitmap mapTexture = new Bitmap(2560, 2560);
1365 Graphics g = Graphics.FromImage(mapTexture);
1366 SolidBrush sea = new SolidBrush(Color.DarkBlue);
1367 g.FillRectangle(sea, 0, 0, 2560, 2560);
1369 for (int i = 0; i < mapBlocks.Count; i++)
1371 ushort x = (ushort)((mapBlocks[i].X - m_scene.RegionInfo.RegionLocX) + 10);
1372 ushort y = (ushort)((mapBlocks[i].Y - m_scene.RegionInfo.RegionLocY) + 10);
1373 g.DrawImage(bitImages[i], (x * 128), 2560 - (y * 128), 128, 128); // y origin is top
1376 mapTexture.Save(exportPath, ImageFormat.Jpeg);
1379 "[WORLD MAP]: Successfully exported world map
for {0} to {1}
",
1380 m_scene.RegionInfo.RegionName, exportPath);
1383 public void HandleGenerateMapConsoleCommand(string module, string[] cmdparams)
1385 Scene consoleScene = m_scene.ConsoleScene();
1387 if (consoleScene != null && consoleScene != m_scene)
1393 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
1398 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
1400 // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots)
1402 OSDMap responsemap = new OSDMap();
1403 int tc = Environment.TickCount;
1404 if (m_scene.GetRootAgentCount() == 0)
1406 OSDMap responsemapdata = new OSDMap();
1407 responsemapdata["X
"] = OSD.FromInteger((int)(xstart + 1));
1408 responsemapdata["Y
"] = OSD.FromInteger((int)(ystart + 1));
1409 responsemapdata["ID
"] = OSD.FromUUID(UUID.Zero);
1410 responsemapdata["Name
"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
1411 responsemapdata["Extra
"] = OSD.FromInteger(0);
1412 responsemapdata["Extra2
"] = OSD.FromInteger(0);
1413 OSDArray responsearr = new OSDArray();
1414 responsearr.Add(responsemapdata);
1416 responsemap["6
"] = responsearr;
1420 OSDArray responsearr = new OSDArray(); // Don't preallocate. MT (m_scene.GetRootAgentCount());
1421 m_scene.ForEachRootScenePresence(delegate (ScenePresence sp)
1423 OSDMap responsemapdata = new OSDMap();
1424 responsemapdata["X
"] = OSD.FromInteger((int)(xstart + sp.AbsolutePosition.X));
1425 responsemapdata["Y
"] = OSD.FromInteger((int)(ystart + sp.AbsolutePosition.Y));
1426 responsemapdata["ID
"] = OSD.FromUUID(UUID.Zero);
1427 responsemapdata["Name
"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
1428 responsemapdata["Extra
"] = OSD.FromInteger(1);
1429 responsemapdata["Extra2
"] = OSD.FromInteger(0);
1430 responsearr.Add(responsemapdata);
1432 responsemap["6
"] = responsearr;
1435 // Service 7/10 (MAP_ITEM_LAND_FOR_SALE/ADULT)
1437 ILandChannel landChannel = m_scene.LandChannel;
1438 List<ILandObject> parcels = landChannel.AllParcels();
1440 if ((parcels != null) && (parcels.Count >= 0))
1442 OSDArray responsearr = new OSDArray(parcels.Count);
1443 foreach (ILandObject parcel_interface in parcels)
1446 if (!(parcel_interface is LandObject))
1449 LandObject land = (LandObject)parcel_interface;
1450 LandData parcel = land.LandData;
1452 // Show land for sale
1453 if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
1455 Vector3 min = parcel.AABBMin;
1456 Vector3 max = parcel.AABBMax;
1457 float x = (min.X + max.X) / 2;
1458 float y = (min.Y + max.Y) / 2;
1460 OSDMap responsemapdata = new OSDMap();
1461 responsemapdata["X
"] = OSD.FromInteger((int)(xstart + x));
1462 responsemapdata["Y
"] = OSD.FromInteger((int)(ystart + y));
1463 // responsemapdata["Z
"] = OSD.FromInteger((int)m_scene.GetGroundHeight(x,y));
1464 responsemapdata["ID
"] = OSD.FromUUID(parcel.GlobalID);
1465 responsemapdata["Name
"] = OSD.FromString(parcel.Name);
1466 responsemapdata["Extra
"] = OSD.FromInteger(parcel.Area);
1467 responsemapdata["Extra2
"] = OSD.FromInteger(parcel.SalePrice);
1468 responsearr.Add(responsemapdata);
1472 if(responsearr.Count > 0)
1474 if(m_scene.RegionInfo.RegionSettings.Maturity == 2)
1475 responsemap["10
"] = responsearr;
1477 responsemap["7
"] = responsearr;
1481 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
1483 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
1486 OSDArray responsearr = new OSDArray();
1487 OSDMap responsemapdata = new OSDMap();
1488 responsemapdata["X
"] = OSD.FromInteger((int)(xstart + sog.AbsolutePosition.X));
1489 responsemapdata["Y
"] = OSD.FromInteger((int)(ystart + sog.AbsolutePosition.Y));
1490 // responsemapdata["Z
"] = OSD.FromInteger((int)m_scene.GetGroundHeight(x,y));
1491 responsemapdata["ID
"] = OSD.FromUUID(sog.UUID);
1492 responsemapdata["Name
"] = OSD.FromString(sog.Name);
1493 responsemapdata["Extra
"] = OSD.FromInteger(0); // color (unused)
1494 responsemapdata["Extra2
"] = OSD.FromInteger(0); // 0 = telehub / 1 = infohub
1495 responsearr.Add(responsemapdata);
1497 responsemap["1
"] = responsearr;
1504 public void GenerateMaptile()
1506 // Cannot create a map for a nonexistent heightmap
1507 if (m_scene.Heightmap == null)
1510 if (m_mapImageGenerator == null)
1512 Console.WriteLine("No map image generator available
for {0}
", m_scene.Name);
1515 m_log.DebugFormat("[WORLD MAP]: Generating map image
for {0}
", m_scene.Name);
1517 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
1519 GenerateMaptile(mapbmp);
1521 if (m_mapImageServiceModule != null)
1522 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
1526 private void GenerateMaptile(Bitmap mapbmp)
1528 bool needRegionSave = false;
1530 // remove old assets
1531 UUID lastID = m_scene.RegionInfo.RegionSettings.TerrainImageID;
1532 if (lastID != UUID.Zero)
1534 m_scene.AssetService.Delete(lastID.ToString());
1535 m_scene.RegionInfo.RegionSettings.TerrainImageID = UUID.Zero;
1536 needRegionSave = true;
1539 lastID = m_scene.RegionInfo.RegionSettings.ParcelImageID;
1540 if (lastID != UUID.Zero)
1542 m_scene.AssetService.Delete(lastID.ToString());
1543 m_scene.RegionInfo.RegionSettings.ParcelImageID = UUID.Zero;
1544 needRegionSave = true;
1553 // if large region limit its size since new viewers will not use it
1554 // but it is still usable for ossl
1555 if(m_scene.RegionInfo.RegionSizeX > Constants.RegionSize ||
1556 m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1558 int bx = mapbmp.Width;
1559 int by = mapbmp.Height;
1563 if(mb > 2 * Constants.RegionSize && mb > 0)
1565 float scale = 2.0f * (float)Constants.RegionSize/(float)mb;
1566 Size newsize = new Size();
1567 newsize.Width = (int)(bx * scale);
1568 newsize.Height = (int)(by * scale);
1570 using(Bitmap scaledbmp = new Bitmap(mapbmp,newsize))
1571 data = OpenJPEG.EncodeFromImage(scaledbmp, true);
1574 data = OpenJPEG.EncodeFromImage(mapbmp, true);
1577 data = OpenJPEG.EncodeFromImage(mapbmp, true);
1579 if (data != null && data.Length > 0)
1581 UUID terrainImageID = UUID.Random();
1583 AssetBase asset = new AssetBase(
1585 "terrainImage_
" + m_scene.RegionInfo.RegionID.ToString(),
1586 (sbyte)AssetType.Texture,
1587 m_scene.RegionInfo.RegionID.ToString());
1589 asset.Description = m_scene.RegionInfo.RegionName;
1590 asset.Temporary = false;
1591 asset.Flags = AssetFlags.Maptile;
1593 // Store the new one
1594 m_log.DebugFormat("[WORLD MAP]: Storing map tile {0}
for {1}
", asset.ID, m_scene.RegionInfo.RegionName);
1596 m_scene.AssetService.Store(asset);
1598 m_scene.RegionInfo.RegionSettings.TerrainImageID = terrainImageID;
1599 needRegionSave = true;
1604 m_log.Error("[WORLD MAP]: Failed generating terrain map:
" + e);
1608 // V2/3 still seem to need this, or we are missing something somewhere
1609 byte[] overlay = GenerateOverlay();
1610 if (overlay != null)
1612 UUID parcelImageID = UUID.Random();
1614 AssetBase parcels = new AssetBase(
1616 "parcelImage_
" + m_scene.RegionInfo.RegionID.ToString(),
1617 (sbyte)AssetType.Texture,
1618 m_scene.RegionInfo.RegionID.ToString());
1619 parcels.Data = overlay;
1620 parcels.Description = m_scene.RegionInfo.RegionName;
1621 parcels.Temporary = false;
1622 parcels.Flags = AssetFlags.Maptile;
1624 m_scene.AssetService.Store(parcels);
1626 m_scene.RegionInfo.RegionSettings.ParcelImageID = parcelImageID;
1627 needRegionSave = true;
1631 m_scene.RegionInfo.RegionSettings.Save();
1634 private void MakeRootAgent(ScenePresence avatar)
1638 if (!m_rootAgents.Contains(avatar.UUID))
1640 m_rootAgents.Add(avatar.UUID);
1645 private void MakeChildAgent(ScenePresence avatar)
1649 m_rootAgents.Remove(avatar.UUID);
1652 lock (m_mapBlockRequestEvent)
1654 if (m_mapBlockRequests.ContainsKey(avatar.UUID))
1655 m_mapBlockRequests.Remove(avatar.UUID);
1659 public void OnRegionUp(GridRegion otherRegion)
1661 ulong regionhandle = otherRegion.RegionHandle;
1662 string httpserver = otherRegion.ServerURI + "MAP/MapItems/
" + regionhandle.ToString();
1664 lock (m_blacklistedregions)
1666 if (m_blacklistedregions.Contains(regionhandle))
1667 m_blacklistedregions.Remove(regionhandle);
1670 lock (m_blacklistedurls)
1672 if (m_blacklistedurls.Contains(httpserver))
1673 m_blacklistedurls.Remove(httpserver);
1676 lock (m_cachedRegionMapItemsAddress)
1678 m_cachedRegionMapItemsAddress.AddOrUpdate(regionhandle,
1679 httpserver, 5.0 * expireBlackListTime);
1683 private Byte[] GenerateOverlay()
1685 int landTileSize = LandManagementModule.LandUnit;
1687 // These need to be ints for bitmap generation
1688 int regionSizeX = (int)m_scene.RegionInfo.RegionSizeX;
1689 int regionLandTilesX = regionSizeX / landTileSize;
1691 int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY;
1692 int regionLandTilesY = regionSizeY / landTileSize;
1694 bool landForSale = false;
1697 // scan terrain avoiding potencial merges of large bitmaps
1698 //TODO create the sell bitmap at landchannel / landmaster ?
1699 // and auction also, still not suported
1701 bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY];
1702 for (int x = 0, xx = 0; x < regionLandTilesX; x++ ,xx += landTileSize)
1704 for (int y = 0, yy = 0; y < regionLandTilesY; y++, yy += landTileSize)
1706 land = m_scene.LandChannel.GetLandObject(xx, yy);
1707 if (land != null && (land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
1709 saleBitmap[x, y] = true;
1713 saleBitmap[x, y] = false;
1719 m_log.DebugFormat("[WORLD MAP]:
Region {0} has no parcels
for sale, not generating overlay
", m_scene.RegionInfo.RegionName);
1723 m_log.DebugFormat("[WORLD MAP]:
Region {0} has parcels
for sale, generating overlay
", m_scene.RegionInfo.RegionName);
1725 using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY))
1727 Color background = Color.FromArgb(0, 0, 0, 0);
1729 using (Graphics g = Graphics.FromImage(overlay))
1731 using (SolidBrush transparent = new SolidBrush(background))
1732 g.FillRectangle(transparent, 0, 0, regionSizeX, regionSizeY);
1734 // make it a bit transparent
1735 using (SolidBrush yellow = new SolidBrush(Color.FromArgb(192, 249, 223, 9)))
1737 for (int x = 0; x < regionLandTilesX; x++)
1739 for (int y = 0; y < regionLandTilesY; y++)
1741 if (saleBitmap[x, y])
1745 regionSizeX - landTileSize - (y * landTileSize),
1755 return OpenJPEG.EncodeFromImage(overlay, true);
1759 m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay:
" + e.ToString());
1767 public class MapRequestState
1769 public UUID agentID;
1771 public uint EstateID;
1772 public bool godlike;
1773 public uint itemtype;
1774 public ulong regionhandle;
1777 public struct MapBlockRequestData
1779 public IClientAPI client;
static OSDMapLayer GetOSDMapLayerResponse()
delegate void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
OpenSim.Framework.Capabilities.Caps Caps
virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
void RequestMapItems(string httpserver, UUID id, uint flags, uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
Enqueue the MapItem request for remote processing
virtual void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
OpenMetaverse.StructuredData.OSDArray OSDArray
virtual void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void OnRegisterCaps(UUID agentID, Caps caps)
UUID GlobalID
Global ID for the parcel. (3rd Party Integration)
string MapLayerRequest(string request, string path, string param, UUID agentID, Caps caps)
Callback for a map layer request
Keeps track of a specific piece of land's information
OpenMetaverse.StructuredData.OSDMap OSDMap
void process()
Processing thread main() loop for doing remote mapitem requests
virtual void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
override Vector3 AbsolutePosition
Position of this avatar relative to the region the avatar is in
Details of a Parcel of land
OpenSim.Services.Interfaces.GridRegion GridRegion
OpenMetaverse.StructuredData.OSD OSD
virtual void RemoveHandlers()
virtual void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
virtual void AddHandlers()
override Vector3 AbsolutePosition
The absolute position of this scene object in the scene
uint Flags
Parcel settings. Access flags, Fly, NoPush, Voice, Scripts allowed, etc. ParcelFlags ...
int SalePrice
When the parcel is being sold, this is the price to purchase the parcel
OpenSim.Services.Interfaces.GridRegion GridRegion
override string Name
The name of an object grouping is always the same as its root part
int Area
Area in meters^2 the parcel contains
virtual void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...