opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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.Reflection;
31 using System.Net;
32 using System.IO;
33 using System.Timers;
34 using System.Drawing;
35 using System.Drawing.Imaging;
36  
37 using log4net;
38 using Mono.Addins;
39 using Nini.Config;
40 using OpenSim.Framework;
41 using OpenSim.Region.Framework.Interfaces;
42 using OpenSim.Region.Framework.Scenes;
43 using OpenSim.Services.Interfaces;
44 using OpenSim.Server.Base;
45 using OpenMetaverse;
46 using OpenMetaverse.StructuredData;
47  
48 namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
49 {
50 /// <summary>
51 /// </summary>
52 /// <remarks>
53 /// </remarks>
54  
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MapImageServiceModule")]
56 public class MapImageServiceModule : ISharedRegionModule
57 {
58 private static readonly ILog m_log =
59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 private static string LogHeader = "[MAP IMAGE SERVICE MODULE]";
61  
62 private bool m_enabled = false;
63 private IMapImageService m_MapService;
64  
65 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
66  
67 private int m_refreshtime = 0;
68 private int m_lastrefresh = 0;
69 private System.Timers.Timer m_refreshTimer = new System.Timers.Timer();
70  
71 #region ISharedRegionModule
72  
73 public Type ReplaceableInterface { get { return null; } }
74 public string Name { get { return "MapImageServiceModule"; } }
75 public void RegionLoaded(Scene scene) { }
76 public void Close() { }
77 public void PostInitialise() { }
78  
79 ///<summary>
80 ///
81 ///</summary>
82 public void Initialise(IConfigSource source)
83 {
84 IConfig moduleConfig = source.Configs["Modules"];
85 if (moduleConfig != null)
86 {
87 string name = moduleConfig.GetString("MapImageService", "");
88 if (name != Name)
89 return;
90 }
91  
92 IConfig config = source.Configs["MapImageService"];
93 if (config == null)
94 return;
95  
96 int refreshminutes = Convert.ToInt32(config.GetString("RefreshTime"));
97 if (refreshminutes <= 0)
98 {
99 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: No refresh time given in config. Module disabled.");
100 return;
101 }
102  
103 m_refreshtime = refreshminutes * 60 * 1000; // convert from minutes to ms
104  
105 string service = config.GetString("LocalServiceModule", string.Empty);
106 if (service == string.Empty)
107 {
108 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: No service dll given in config. Unable to proceed.");
109 return;
110 }
111  
112 Object[] args = new Object[] { source };
113 m_MapService = ServerUtils.LoadPlugin<IMapImageService>(service, args);
114 if (m_MapService == null)
115 {
116 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Unable to load LocalServiceModule from {0}. MapService module disabled. Please fix the configuration.", service);
117 return;
118 }
119  
120 m_refreshTimer.Enabled = true;
121 m_refreshTimer.AutoReset = true;
122 m_refreshTimer.Interval = m_refreshtime;
123 m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
124  
125 m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with refresh time {0}min and service object {1}",
126 refreshminutes, service);
127  
128 m_enabled = true;
129 }
130  
131 ///<summary>
132 ///
133 ///</summary>
134 public void AddRegion(Scene scene)
135 {
136 if (!m_enabled)
137 return;
138  
139 // Every shared region module has to maintain an indepedent list of
140 // currently running regions
141 lock (m_scenes)
142 m_scenes[scene.RegionInfo.RegionID] = scene;
143  
144 scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) UploadMapTile(s); };
145 }
146  
147 ///<summary>
148 ///
149 ///</summary>
150 public void RemoveRegion(Scene scene)
151 {
152 if (! m_enabled)
153 return;
154  
155 lock (m_scenes)
156 m_scenes.Remove(scene.RegionInfo.RegionID);
157 }
158  
159 #endregion ISharedRegionModule
160  
161 ///<summary>
162 ///
163 ///</summary>
164 private void HandleMaptileRefresh(object sender, EventArgs ea)
165 {
166 // this approach is a bit convoluted becase we want to wait for the
167 // first upload to happen on startup but after all the objects are
168 // loaded and initialized
169 if (m_lastrefresh > 0 && Util.EnvironmentTickCountSubtract(m_lastrefresh) < m_refreshtime)
170 return;
171  
172 m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: map refresh!");
173 lock (m_scenes)
174 {
175 foreach (IScene scene in m_scenes.Values)
176 {
177 try
178 {
179 UploadMapTile(scene);
180 }
181 catch (Exception ex)
182 {
183 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: something bad happened {0}", ex.Message);
184 }
185 }
186 }
187  
188 m_lastrefresh = Util.EnvironmentTickCount();
189 }
190  
191 ///<summary>
192 ///
193 ///</summary>
194 private void UploadMapTile(IScene scene)
195 {
196 m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.RegionInfo.RegionName);
197 string regionName = scene.RegionInfo.RegionName;
198  
199 // Create a JPG map tile and upload it to the AddMapTile API
200 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
201 if (tileGenerator == null)
202 {
203 m_log.WarnFormat("{0} Cannot upload map tile without an ImageGenerator", LogHeader);
204 return;
205 }
206 using (Bitmap mapTile = tileGenerator.CreateMapTile())
207 {
208 if (mapTile != null)
209 {
210 // mapTile.Save( // DEBUG DEBUG
211 // String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY),
212 // ImageFormat.Jpeg);
213 // If the region/maptile is legacy sized, just upload the one tile like it has always been done
214 if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
215 {
216 ConvertAndUploadMaptile(mapTile,
217 scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
218 scene.RegionInfo.RegionName);
219 }
220 else
221 {
222 // For larger regions (varregion) we must cut the region image into legacy sized
223 // pieces since that is how the maptile system works.
224 // Note the assumption that varregions are always a multiple of legacy size.
225 for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
226 {
227 for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
228 {
229 // Images are addressed from the upper left corner so have to do funny
230 // math to pick out the sub-tile since regions are numbered from
231 // the lower left.
232 Rectangle rect = new Rectangle(
233 (int)xx,
234 mapTile.Height - (int)yy - (int)Constants.RegionSize,
235 (int)Constants.RegionSize, (int)Constants.RegionSize);
236 using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
237 {
238 ConvertAndUploadMaptile(subMapTile,
239 scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize),
240 scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize),
241 regionName);
242 }
243 }
244 }
245 }
246 }
247 else
248 {
249 m_log.WarnFormat("{0} Tile image generation failed", LogHeader);
250 }
251 }
252 }
253  
254 private void ConvertAndUploadMaptile(Image tileImage, uint locX, uint locY, string regionName)
255 {
256 byte[] jpgData = Utils.EmptyBytes;
257  
258 using (MemoryStream stream = new MemoryStream())
259 {
260 tileImage.Save(stream, ImageFormat.Jpeg);
261 jpgData = stream.ToArray();
262 }
263 if (jpgData != Utils.EmptyBytes)
264 {
265 string reason = string.Empty;
266 if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, out reason))
267 {
268 m_log.DebugFormat("{0} Unable to upload tile image for {1} at {2}-{3}: {4}", LogHeader,
269 regionName, locX, locY, reason);
270 }
271 }
272 else
273 {
274 m_log.WarnFormat("{0} Tile image generation failed for region {1}", LogHeader, regionName);
275 }
276 }
277 }
278 }