OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SimianGridMaptileModule.cs
Go to the documentation of this file.
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 
28 using System;
29 using System.Collections.Generic;
30 using System.Collections.Specialized;
31 using System.Reflection;
32 using System.Net;
33 using System.IO;
34 using System.Timers;
35 using System.Drawing;
36 using System.Drawing.Imaging;
37 
38 using log4net;
39 using Mono.Addins;
40 using Nini.Config;
41 using OpenSim.Framework;
42 using OpenSim.Region.Framework.Interfaces;
43 using OpenSim.Region.Framework.Scenes;
44 using OpenMetaverse;
45 using OpenMetaverse.StructuredData;
46 
47 //namespace OpenSim.Region.OptionalModules.Simian
48 namespace OpenSim.Services.Connectors.SimianGrid
49 {
54 
55  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianGridMaptile")]
57  {
58  private static readonly ILog m_log =
59  LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 
61  private bool m_enabled = false;
62  private string m_serverUrl = String.Empty;
63  private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
64 
65  private int m_refreshtime = 0;
66  private int m_lastrefresh = 0;
67  private System.Timers.Timer m_refreshTimer = new System.Timers.Timer();
68 
69  #region ISharedRegionModule
70 
71  public Type ReplaceableInterface { get { return null; } }
72  public string Name { get { return "SimianGridMaptile"; } }
73  public void RegionLoaded(Scene scene) { }
74  public void Close() { }
75 
79  public void Initialise(IConfigSource source)
80  {
81  IConfig config = source.Configs["SimianGridMaptiles"];
82  if (config == null)
83  return;
84 
85  if (! config.GetBoolean("Enabled", false))
86  return;
87 
88  m_serverUrl = config.GetString("MaptileURL");
89  if (String.IsNullOrEmpty(m_serverUrl))
90  return;
91 
92  int refreshseconds = Convert.ToInt32(config.GetString("RefreshTime"));
93  if (refreshseconds <= 0)
94  return;
95 
96  m_refreshtime = refreshseconds * 1000; // convert from seconds to ms
97  m_log.InfoFormat("[SIMIAN MAPTILE] enabled with refresh timeout {0} and URL {1}",
98  m_refreshtime,m_serverUrl);
99 
100  m_enabled = true;
101  }
102 
106  public void PostInitialise()
107  {
108  if (m_enabled)
109  {
110  m_refreshTimer.Enabled = true;
111  m_refreshTimer.AutoReset = true;
112  m_refreshTimer.Interval = 5 * 60 * 1000; // every 5 minutes
113  m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
114  }
115  }
116 
117 
121  public void AddRegion(Scene scene)
122  {
123  if (! m_enabled)
124  return;
125 
126  // Every shared region module has to maintain an indepedent list of
127  // currently running regions
128  lock (m_scenes)
129  m_scenes[scene.RegionInfo.RegionID] = scene;
130  }
131 
135  public void RemoveRegion(Scene scene)
136  {
137  if (! m_enabled)
138  return;
139 
140  lock (m_scenes)
141  m_scenes.Remove(scene.RegionInfo.RegionID);
142  }
143 
144  #endregion ISharedRegionModule
145 
149  private void HandleMaptileRefresh(object sender, EventArgs ea)
150  {
151  // this approach is a bit convoluted becase we want to wait for the
152  // first upload to happen on startup but after all the objects are
153  // loaded and initialized
154  if (m_lastrefresh > 0 && Util.EnvironmentTickCountSubtract(m_lastrefresh) < m_refreshtime)
155  return;
156 
157  m_log.DebugFormat("[SIMIAN MAPTILE] map refresh fired");
158  lock (m_scenes)
159  {
160  foreach (IScene scene in m_scenes.Values)
161  {
162  try
163  {
164  UploadMapTile(scene);
165  }
166  catch (Exception ex)
167  {
168  m_log.WarnFormat("[SIMIAN MAPTILE] something bad happened {0}",ex.Message);
169  }
170  }
171  }
172 
173  m_lastrefresh = Util.EnvironmentTickCount();
174  }
175 
179  private void UploadMapTile(IScene scene)
180  {
181  m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for {0}",scene.RegionInfo.RegionName);
182 
183  // Create a PNG map tile and upload it to the AddMapTile API
184  IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
185  if (tileGenerator == null)
186  {
187  m_log.Warn("[SIMIAN MAPTILE]: Cannot upload PNG map tile without an ImageGenerator");
188  return;
189  }
190 
191  using (Bitmap mapTile = tileGenerator.CreateMapTile())
192  {
193  if (mapTile != null)
194  {
195  // If the region/maptile is legacy sized, just upload the one tile like it has always been done
196  if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
197  {
198  ConvertAndUploadMaptile(mapTile, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY);
199  }
200  else
201  {
202  // For larger regions (varregion) we must cut the region image into legacy sized
203  // pieces since that is how the maptile system works.
204  // Note the assumption that varregions are always a multiple of legacy size.
205  for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
206  {
207  for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
208  {
209  // Images are addressed from the upper left corner so have to do funny
210  // math to pick out the sub-tile since regions are numbered from
211  // the lower left.
212  Rectangle rect = new Rectangle(
213  (int)xx,
214  mapTile.Height - (int)yy - (int)Constants.RegionSize,
216 
217  using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
218  {
219  uint locX = scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize);
220  uint locY = scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize);
221 
222  ConvertAndUploadMaptile(subMapTile, locX, locY);
223  }
224  }
225  }
226  }
227  }
228  else
229  {
230  m_log.WarnFormat("[SIMIAN MAPTILE] Tile image generation failed");
231  }
232  }
233 
234  }
235 
239  private void ConvertAndUploadMaptile(Image mapTile, uint locX, uint locY)
240  {
241  //m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for location {0}, {1}", locX, locY);
242 
243  byte[] pngData = Utils.EmptyBytes;
244  using (MemoryStream stream = new MemoryStream())
245  {
246  mapTile.Save(stream, ImageFormat.Png);
247  pngData = stream.ToArray();
248  }
249 
250  NameValueCollection requestArgs = new NameValueCollection
251  {
252  { "RequestMethod", "xAddMapTile" },
253  { "X", locX.ToString() },
254  { "Y", locY.ToString() },
255  { "ContentType", "image/png" },
256  { "EncodedData", System.Convert.ToBase64String(pngData) }
257  };
258 
259  OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
260  if (! response["Success"].AsBoolean())
261  {
262  m_log.WarnFormat("[SIMIAN MAPTILE] failed to store map tile; {0}",response["Message"].AsString());
263  }
264  }
265  }
266 }
RegionInfo RegionInfo
Definition: IScene.cs:64
OpenMetaverse.StructuredData.OSDMap OSDMap
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
uint RegionLocY
The y co-ordinate of this region in map tiles (e.g. 1000). Coordinate is scaled as world coordinates ...
Definition: RegionInfo.cs:496
uint RegionLocX
The x co-ordinate of this region in map tiles (e.g. 1000). Coordinate is scaled as world coordinates ...
Definition: RegionInfo.cs:485