clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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 {
50 /// <summary>
51 /// </summary>
52 /// <remarks>
53 /// </remarks>
54  
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianGridMaptile")]
56 public class SimianGridMaptile : ISharedRegionModule
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  
76 ///<summary>
77 ///
78 ///</summary>
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  
103 ///<summary>
104 ///
105 ///</summary>
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  
118 ///<summary>
119 ///
120 ///</summary>
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  
132 ///<summary>
133 ///
134 ///</summary>
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  
146 ///<summary>
147 ///
148 ///</summary>
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  
176 ///<summary>
177 ///
178 ///</summary>
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,
215 (int)Constants.RegionSize, (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  
236 ///<summary>
237 ///
238 ///</summary>
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 }