aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/WorldMap
diff options
context:
space:
mode:
authorDr Scofield2009-02-10 13:10:57 +0000
committerDr Scofield2009-02-10 13:10:57 +0000
commit180be7de07014aa33bc6066f12a0819b731c1c9d (patch)
tree3aa13af3cda4b808fa9453655875327699b61311 /OpenSim/Region/CoreModules/World/WorldMap
parentStopgap measure: To use gridlaunch, or GUI, start opensim with (diff)
downloadopensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.zip
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.gz
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.bz2
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.xz
this is step 2 of 2 of the OpenSim.Region.Environment refactor.
NOTHING has been deleted or moved off to forge at this point. what has happened is that OpenSim.Region.Environment.Modules has been split in two: - OpenSim.Region.CoreModules: all those modules that are either directly or indirectly referenced from other OpenSim packages, or that provide functionality that the OpenSim developer community considers core functionality: CoreModules/Agent/AssetTransaction CoreModules/Agent/Capabilities CoreModules/Agent/TextureDownload CoreModules/Agent/TextureSender CoreModules/Agent/TextureSender/Tests CoreModules/Agent/Xfer CoreModules/Avatar/AvatarFactory CoreModules/Avatar/Chat/ChatModule CoreModules/Avatar/Combat CoreModules/Avatar/Currency/SampleMoney CoreModules/Avatar/Dialog CoreModules/Avatar/Friends CoreModules/Avatar/Gestures CoreModules/Avatar/Groups CoreModules/Avatar/InstantMessage CoreModules/Avatar/Inventory CoreModules/Avatar/Inventory/Archiver CoreModules/Avatar/Inventory/Transfer CoreModules/Avatar/Lure CoreModules/Avatar/ObjectCaps CoreModules/Avatar/Profiles CoreModules/Communications/Local CoreModules/Communications/REST CoreModules/Framework/EventQueue CoreModules/Framework/InterfaceCommander CoreModules/Hypergrid CoreModules/InterGrid CoreModules/Scripting/DynamicTexture CoreModules/Scripting/EMailModules CoreModules/Scripting/HttpRequest CoreModules/Scripting/LoadImageURL CoreModules/Scripting/VectorRender CoreModules/Scripting/WorldComm CoreModules/Scripting/XMLRPC CoreModules/World/Archiver CoreModules/World/Archiver/Tests CoreModules/World/Estate CoreModules/World/Land CoreModules/World/Permissions CoreModules/World/Serialiser CoreModules/World/Sound CoreModules/World/Sun CoreModules/World/Terrain CoreModules/World/Terrain/DefaultEffects CoreModules/World/Terrain/DefaultEffects/bin CoreModules/World/Terrain/DefaultEffects/bin/Debug CoreModules/World/Terrain/Effects CoreModules/World/Terrain/FileLoaders CoreModules/World/Terrain/FloodBrushes CoreModules/World/Terrain/PaintBrushes CoreModules/World/Terrain/Tests CoreModules/World/Vegetation CoreModules/World/Wind CoreModules/World/WorldMap - OpenSim.Region.OptionalModules: all those modules that are not core modules: OptionalModules/Avatar/Chat/IRC-stuff OptionalModules/Avatar/Concierge OptionalModules/Avatar/Voice/AsterixVoice OptionalModules/Avatar/Voice/SIPVoice OptionalModules/ContentManagementSystem OptionalModules/Grid/Interregion OptionalModules/Python OptionalModules/SvnSerialiser OptionalModules/World/NPC OptionalModules/World/TreePopulator
Diffstat (limited to 'OpenSim/Region/CoreModules/World/WorldMap')
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs39
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs586
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs172
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs249
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs411
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs905
6 files changed, 2362 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs b/OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs
new file mode 100644
index 0000000..3684df0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs
@@ -0,0 +1,39 @@
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 OpenSim 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
28using System.Drawing;
29using OpenSim.Region.Framework.Scenes;
30using Nini.Config;
31
32namespace OpenSim.Region.CoreModules.World.WorldMap
33{
34 public interface IMapTileTerrainRenderer
35 {
36 void Initialise(Scene scene, IConfigSource config);
37 void TerrainToBitmap(Bitmap mapbmp);
38 }
39}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs
new file mode 100644
index 0000000..eea6cf6
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs
@@ -0,0 +1,586 @@
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 OpenSim 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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Drawing2D;
33using System.Drawing.Imaging;
34using System.Reflection;
35using Nini.Config;
36using OpenMetaverse.Imaging;
37using log4net;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenMetaverse;
41
42namespace OpenSim.Region.CoreModules.World.WorldMap
43{
44 public enum DrawRoutine
45 {
46 Rectangle,
47 Polygon,
48 Ellipse
49 }
50
51 public struct face
52 {
53 public Point[] pts;
54 }
55
56 public struct DrawStruct
57 {
58 public DrawRoutine dr;
59 public Rectangle rect;
60 public SolidBrush brush;
61 public face[] trns;
62 }
63
64 public class MapImageModule : IMapImageGenerator, IRegionModule
65 {
66 private static readonly ILog m_log =
67 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 private Scene m_scene;
70 private IConfigSource m_config;
71 private IMapTileTerrainRenderer terrainRenderer;
72
73 #region IMapImageGenerator Members
74
75 public byte[] WriteJpeg2000Image(string gradientmap)
76 {
77 byte[] imageData = null;
78
79 bool drawPrimVolume = true;
80 bool textureTerrain = true;
81
82 try
83 {
84 IConfig startupConfig = m_config.Configs["Startup"];
85 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume);
86 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain);
87 }
88 catch
89 {
90 m_log.Warn("[MAPTILE]: Failed to load StartupConfig");
91 }
92
93 if (textureTerrain)
94 {
95 terrainRenderer = new TexturedMapTileRenderer();
96 }
97 else
98 {
99 terrainRenderer = new ShadedMapTileRenderer();
100 }
101 terrainRenderer.Initialise(m_scene, m_config);
102
103 Bitmap mapbmp = new Bitmap(256, 256);
104 //long t = System.Environment.TickCount;
105 //for (int i = 0; i < 10; ++i) {
106 terrainRenderer.TerrainToBitmap(mapbmp);
107 //}
108 //t = System.Environment.TickCount - t;
109 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t);
110
111
112 if (drawPrimVolume)
113 {
114 DrawObjectVolume(m_scene, mapbmp);
115 }
116
117 try
118 {
119 imageData = OpenJPEG.EncodeFromImage(mapbmp, true);
120 }
121 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
122 {
123 Console.WriteLine("Failed generating terrain map: " + e);
124 }
125
126 return imageData;
127 }
128
129 #endregion
130
131 #region IRegionModule Members
132
133 public void Initialise(Scene scene, IConfigSource source)
134 {
135 m_scene = scene;
136 m_config = source;
137
138 IConfig startupConfig = m_config.Configs["Startup"];
139 if (startupConfig.GetString("MapImageModule", "MapImageModule") !=
140 "MapImageModule")
141 return;
142
143 m_scene.RegisterModuleInterface<IMapImageGenerator>(this);
144 }
145
146 public void PostInitialise()
147 {
148 }
149
150 public void Close()
151 {
152 }
153
154 public string Name
155 {
156 get { return "MapImageModule"; }
157 }
158
159 public bool IsSharedModule
160 {
161 get { return false; }
162 }
163
164 #endregion
165
166// TODO: unused:
167// private void ShadeBuildings(Bitmap map)
168// {
169// lock (map)
170// {
171// lock (m_scene.Entities)
172// {
173// foreach (EntityBase entity in m_scene.Entities.Values)
174// {
175// if (entity is SceneObjectGroup)
176// {
177// SceneObjectGroup sog = (SceneObjectGroup) entity;
178//
179// foreach (SceneObjectPart primitive in sog.Children.Values)
180// {
181// int x = (int) (primitive.AbsolutePosition.X - (primitive.Scale.X / 2));
182// int y = (int) (primitive.AbsolutePosition.Y - (primitive.Scale.Y / 2));
183// int w = (int) primitive.Scale.X;
184// int h = (int) primitive.Scale.Y;
185//
186// int dx;
187// for (dx = x; dx < x + w; dx++)
188// {
189// int dy;
190// for (dy = y; dy < y + h; dy++)
191// {
192// if (x < 0 || y < 0)
193// continue;
194// if (x >= map.Width || y >= map.Height)
195// continue;
196//
197// map.SetPixel(dx, dy, Color.DarkGray);
198// }
199// }
200// }
201// }
202// }
203// }
204// }
205// }
206
207 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
208 {
209 int tc = 0;
210 double[,] hm = whichScene.Heightmap.GetDoubles();
211 tc = System.Environment.TickCount;
212 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
213 List<EntityBase> objs = whichScene.GetEntities();
214 Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
215 //SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>();
216 List<float> z_sortheights = new List<float>();
217 List<uint> z_localIDs = new List<uint>();
218
219 lock (objs)
220 {
221 foreach (EntityBase obj in objs)
222 {
223 // Only draw the contents of SceneObjectGroup
224 if (obj is SceneObjectGroup)
225 {
226 SceneObjectGroup mapdot = (SceneObjectGroup)obj;
227 Color mapdotspot = Color.Gray; // Default color when prim color is white
228 // Loop over prim in group
229 foreach (SceneObjectPart part in mapdot.Children.Values)
230 {
231 if (part == null)
232 continue;
233
234 // Draw if the object is at least 1 meter wide in any direction
235 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
236 {
237 // Try to get the RGBA of the default texture entry..
238 //
239 try
240 {
241 // get the null checks out of the way
242 // skip the ones that break
243 if (part == null)
244 continue;
245
246 if (part.Shape == null)
247 continue;
248
249 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
250 continue; // eliminates trees from this since we don't really have a good tree representation
251 // if you want tree blocks on the map comment the above line and uncomment the below line
252 //mapdotspot = Color.PaleGreen;
253
254 if (part.Shape.Textures == null)
255 continue;
256
257 if (part.Shape.Textures.DefaultTexture == null)
258 continue;
259
260 Color4 texcolor = part.Shape.Textures.DefaultTexture.RGBA;
261
262 // Not sure why some of these are null, oh well.
263
264 int colorr = 255 - (int)(texcolor.R * 255f);
265 int colorg = 255 - (int)(texcolor.G * 255f);
266 int colorb = 255 - (int)(texcolor.B * 255f);
267
268 if (!(colorr == 255 && colorg == 255 && colorb == 255))
269 {
270 //Try to set the map spot color
271 try
272 {
273 // If the color gets goofy somehow, skip it *shakes fist at Color4
274 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
275 }
276 catch (ArgumentException)
277 {
278 }
279 }
280 }
281 catch (IndexOutOfRangeException)
282 {
283 // Windows Array
284 }
285 catch (ArgumentOutOfRangeException)
286 {
287 // Mono Array
288 }
289
290 Vector3 pos = part.GetWorldPosition();
291
292 // skip prim outside of retion
293 if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
294 continue;
295
296 // skip prim in non-finite position
297 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
298 Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
299 continue;
300
301 // Figure out if object is under 256m above the height of the terrain
302 bool isBelow256AboveTerrain = false;
303
304 try
305 {
306 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
307 }
308 catch (Exception)
309 {
310 }
311
312 if (isBelow256AboveTerrain)
313 {
314 // Translate scale by rotation so scale is represented properly when object is rotated
315 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
316 Vector3 scale = new Vector3();
317 Vector3 tScale = new Vector3();
318 Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
319
320 Quaternion llrot = part.GetWorldRotation();
321 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
322 scale = lscale * rot;
323
324 // negative scales don't work in this situation
325 scale.X = Math.Abs(scale.X);
326 scale.Y = Math.Abs(scale.Y);
327 scale.Z = Math.Abs(scale.Z);
328
329 // This scaling isn't very accurate and doesn't take into account the face rotation :P
330 int mapdrawstartX = (int)(pos.X - scale.X);
331 int mapdrawstartY = (int)(pos.Y - scale.Y);
332 int mapdrawendX = (int)(pos.X + scale.X);
333 int mapdrawendY = (int)(pos.Y + scale.Y);
334
335 // If object is beyond the edge of the map, don't draw it to avoid errors
336 if (mapdrawstartX < 0 || mapdrawstartX > 255 || mapdrawendX < 0 || mapdrawendX > 255
337 || mapdrawstartY < 0 || mapdrawstartY > 255 || mapdrawendY < 0
338 || mapdrawendY > 255)
339 continue;
340
341#region obb face reconstruction part duex
342 Vector3[] vertexes = new Vector3[8];
343
344 // float[] distance = new float[6];
345 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
346 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
347 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
348 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
349
350 tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
351 scale = ((tScale * rot));
352 vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
353 // vertexes[0].x = pos.X + vertexes[0].x;
354 //vertexes[0].y = pos.Y + vertexes[0].y;
355 //vertexes[0].z = pos.Z + vertexes[0].z;
356
357 FaceA[0] = vertexes[0];
358 FaceB[3] = vertexes[0];
359 FaceA[4] = vertexes[0];
360
361 tScale = lscale;
362 scale = ((tScale * rot));
363 vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
364
365 // vertexes[1].x = pos.X + vertexes[1].x;
366 // vertexes[1].y = pos.Y + vertexes[1].y;
367 //vertexes[1].z = pos.Z + vertexes[1].z;
368
369 FaceB[0] = vertexes[1];
370 FaceA[1] = vertexes[1];
371 FaceC[4] = vertexes[1];
372
373 tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
374 scale = ((tScale * rot));
375
376 vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
377
378 //vertexes[2].x = pos.X + vertexes[2].x;
379 //vertexes[2].y = pos.Y + vertexes[2].y;
380 //vertexes[2].z = pos.Z + vertexes[2].z;
381
382 FaceC[0] = vertexes[2];
383 FaceD[3] = vertexes[2];
384 FaceC[5] = vertexes[2];
385
386 tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
387 scale = ((tScale * rot));
388 vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
389
390 //vertexes[3].x = pos.X + vertexes[3].x;
391 // vertexes[3].y = pos.Y + vertexes[3].y;
392 // vertexes[3].z = pos.Z + vertexes[3].z;
393
394 FaceD[0] = vertexes[3];
395 FaceC[1] = vertexes[3];
396 FaceA[5] = vertexes[3];
397
398 tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
399 scale = ((tScale * rot));
400 vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
401
402 // vertexes[4].x = pos.X + vertexes[4].x;
403 // vertexes[4].y = pos.Y + vertexes[4].y;
404 // vertexes[4].z = pos.Z + vertexes[4].z;
405
406 FaceB[1] = vertexes[4];
407 FaceA[2] = vertexes[4];
408 FaceD[4] = vertexes[4];
409
410 tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
411 scale = ((tScale * rot));
412 vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
413
414 // vertexes[5].x = pos.X + vertexes[5].x;
415 // vertexes[5].y = pos.Y + vertexes[5].y;
416 // vertexes[5].z = pos.Z + vertexes[5].z;
417
418 FaceD[1] = vertexes[5];
419 FaceC[2] = vertexes[5];
420 FaceB[5] = vertexes[5];
421
422 tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
423 scale = ((tScale * rot));
424 vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
425
426 // vertexes[6].x = pos.X + vertexes[6].x;
427 // vertexes[6].y = pos.Y + vertexes[6].y;
428 // vertexes[6].z = pos.Z + vertexes[6].z;
429
430 FaceB[2] = vertexes[6];
431 FaceA[3] = vertexes[6];
432 FaceB[4] = vertexes[6];
433
434 tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
435 scale = ((tScale * rot));
436 vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
437
438 // vertexes[7].x = pos.X + vertexes[7].x;
439 // vertexes[7].y = pos.Y + vertexes[7].y;
440 // vertexes[7].z = pos.Z + vertexes[7].z;
441
442 FaceD[2] = vertexes[7];
443 FaceC[3] = vertexes[7];
444 FaceD[5] = vertexes[7];
445#endregion
446
447 //int wy = 0;
448
449 //bool breakYN = false; // If we run into an error drawing, break out of the
450 // loop so we don't lag to death on error handling
451 DrawStruct ds = new DrawStruct();
452 ds.brush = new SolidBrush(mapdotspot);
453 //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
454
455 ds.trns = new face[FaceA.Length];
456
457 for (int i = 0; i < FaceA.Length; i++)
458 {
459 Point[] working = new Point[5];
460 working[0] = project(FaceA[i], axPos);
461 working[1] = project(FaceB[i], axPos);
462 working[2] = project(FaceD[i], axPos);
463 working[3] = project(FaceC[i], axPos);
464 working[4] = project(FaceA[i], axPos);
465
466 face workingface = new face();
467 workingface.pts = working;
468
469 ds.trns[i] = workingface;
470 }
471
472 z_sort.Add(part.LocalId, ds);
473 z_localIDs.Add(part.LocalId);
474 z_sortheights.Add(pos.Z);
475
476 //for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
477 //{
478 //for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
479 //{
480 //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
481 //try
482 //{
483 // Remember, flip the y!
484 // mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
485 //}
486 //catch (ArgumentException)
487 //{
488 // breakYN = true;
489 //}
490
491 //if (breakYN)
492 // break;
493 //}
494
495 //if (breakYN)
496 // break;
497 //}
498 } // Object is within 256m Z of terrain
499 } // object is at least a meter wide
500 } // loop over group children
501 } // entitybase is sceneobject group
502 } // foreach loop over entities
503
504 float[] sortedZHeights = z_sortheights.ToArray();
505 uint[] sortedlocalIds = z_localIDs.ToArray();
506
507 // Sort prim by Z position
508 Array.Sort(sortedZHeights, sortedlocalIds);
509
510 Graphics g = Graphics.FromImage(mapbmp);
511
512 for (int s = 0; s < sortedZHeights.Length; s++)
513 {
514 if (z_sort.ContainsKey(sortedlocalIds[s]))
515 {
516 DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]];
517 for (int r = 0; r < rectDrawStruct.trns.Length; r++ )
518 {
519 g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts);
520 }
521 //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
522 }
523 }
524
525 g.Dispose();
526 } // lock entities objs
527
528 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Done in " + (System.Environment.TickCount - tc) + " ms");
529 return mapbmp;
530 }
531
532 private Point project(Vector3 point3d, Vector3 originpos)
533 {
534 Point returnpt = new Point();
535 //originpos = point3d;
536 //int d = (int)(256f / 1.5f);
537
538 //Vector3 topos = new Vector3(0, 0, 0);
539 // float z = -point3d.z - topos.z;
540
541 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d);
542 returnpt.Y = (int)(255 - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d)));
543
544 return returnpt;
545 }
546
547// TODO: unused:
548// #region Deprecated Maptile Generation. Adam may update this
549// private Bitmap TerrainToBitmap(string gradientmap)
550// {
551// Bitmap gradientmapLd = new Bitmap(gradientmap);
552//
553// int pallete = gradientmapLd.Height;
554//
555// Bitmap bmp = new Bitmap(m_scene.Heightmap.Width, m_scene.Heightmap.Height);
556// Color[] colours = new Color[pallete];
557//
558// for (int i = 0; i < pallete; i++)
559// {
560// colours[i] = gradientmapLd.GetPixel(0, i);
561// }
562//
563// lock (m_scene.Heightmap)
564// {
565// ITerrainChannel copy = m_scene.Heightmap;
566// for (int y = 0; y < copy.Height; y++)
567// {
568// for (int x = 0; x < copy.Width; x++)
569// {
570// // 512 is the largest possible height before colours clamp
571// int colorindex = (int) (Math.Max(Math.Min(1.0, copy[x, y] / 512.0), 0.0) * (pallete - 1));
572//
573// // Handle error conditions
574// if (colorindex > pallete - 1 || colorindex < 0)
575// bmp.SetPixel(x, copy.Height - y - 1, Color.Red);
576// else
577// bmp.SetPixel(x, copy.Height - y - 1, colours[colorindex]);
578// }
579// }
580// ShadeBuildings(bmp);
581// return bmp;
582// }
583// }
584// #endregion
585 }
586}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
new file mode 100644
index 0000000..45a99a9
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -0,0 +1,172 @@
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 OpenSim 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 */
27using System;
28using System.Reflection;
29using System.Collections.Generic;
30using System.Net;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.Framework.Scenes.Hypergrid;
35using OpenMetaverse;
36using log4net;
37using Nini.Config;
38
39namespace OpenSim.Region.CoreModules.World.WorldMap
40{
41 public class MapSearchModule : IRegionModule
42 {
43 private static readonly ILog m_log =
44 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 Scene m_scene = null; // only need one for communication with GridService
47 List<Scene> m_scenes = new List<Scene>();
48
49 #region IRegionModule Members
50 public void Initialise(Scene scene, IConfigSource source)
51 {
52 if (m_scene == null)
53 {
54 m_scene = scene;
55 }
56
57 m_scenes.Add(scene);
58 scene.EventManager.OnNewClient += OnNewClient;
59 }
60
61 public void PostInitialise()
62 {
63 }
64
65 public void Close()
66 {
67 m_scene = null;
68 m_scenes.Clear();
69 }
70
71 public string Name
72 {
73 get { return "MapSearchModule"; }
74 }
75
76 public bool IsSharedModule
77 {
78 get { return true; }
79 }
80
81 #endregion
82
83 private void OnNewClient(IClientAPI client)
84 {
85 client.OnMapNameRequest += OnMapNameRequest;
86 }
87
88 private void OnMapNameRequest(IClientAPI remoteClient, string mapName)
89 {
90 if (mapName.Length < 3)
91 {
92 remoteClient.SendAlertMessage("Use a search string with at least 3 characters");
93 return;
94 }
95
96 // try to fetch from GridServer
97 List<RegionInfo> regionInfos = m_scene.SceneGridService.RequestNamedRegions(mapName, 20);
98 if (regionInfos == null)
99 {
100 m_log.Warn("[MAPSEARCHMODULE]: RequestNamedRegions returned null. Old gridserver?");
101 // service wasn't available; maybe still an old GridServer. Try the old API, though it will return only one region
102 regionInfos = new List<RegionInfo>();
103 RegionInfo info = m_scene.SceneGridService.RequestClosestRegion(mapName);
104 if (info != null) regionInfos.Add(info);
105 }
106
107 if ((regionInfos.Count == 0) && IsHypergridOn())
108 {
109 // OK, we tried but there are no regions matching that name.
110 // Let's check quickly if this is a domain name, and if so link to it
111 if (mapName.Contains(".") && mapName.Contains(":"))
112 {
113 // It probably is a domain name. Try to link to it.
114 RegionInfo regInfo;
115 Scene cScene = GetClientScene(remoteClient);
116 regInfo = HGHyperlink.TryLinkRegion(cScene, remoteClient, mapName);
117 if (regInfo != null)
118 regionInfos.Add(regInfo);
119 }
120 }
121
122 List<MapBlockData> blocks = new List<MapBlockData>();
123
124 MapBlockData data;
125 if (regionInfos.Count > 0)
126 {
127 foreach (RegionInfo info in regionInfos)
128 {
129 data = new MapBlockData();
130 data.Agents = 0;
131 data.Access = 21; // TODO what's this?
132 data.MapImageId = info.RegionSettings.TerrainImageID;
133 data.Name = info.RegionName;
134 data.RegionFlags = 0; // TODO not used?
135 data.WaterHeight = 0; // not used
136 data.X = (ushort)info.RegionLocX;
137 data.Y = (ushort)info.RegionLocY;
138 blocks.Add(data);
139 }
140 }
141
142 // final block, closing the search result
143 data = new MapBlockData();
144 data.Agents = 0;
145 data.Access = 255;
146 data.MapImageId = UUID.Zero;
147 data.Name = mapName;
148 data.RegionFlags = 0;
149 data.WaterHeight = 0; // not used
150 data.X = 0;
151 data.Y = 0;
152 blocks.Add(data);
153
154 remoteClient.SendMapBlock(blocks, 0);
155 }
156
157 private bool IsHypergridOn()
158 {
159 return (m_scene.SceneGridService is HGSceneCommunicationService);
160 }
161
162 private Scene GetClientScene(IClientAPI client)
163 {
164 foreach (Scene s in m_scenes)
165 {
166 if (client.Scene.RegionInfo.RegionHandle == s.RegionInfo.RegionHandle)
167 return s;
168 }
169 return m_scene;
170 }
171 }
172}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs
new file mode 100644
index 0000000..b783d7c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs
@@ -0,0 +1,249 @@
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 OpenSim 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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Drawing2D;
33using System.Drawing.Imaging;
34using System.Reflection;
35using OpenMetaverse;
36using OpenMetaverse.Imaging;
37using Nini.Config;
38using log4net;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.World.WorldMap
43{
44 public class ShadedMapTileRenderer : IMapTileTerrainRenderer
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private Scene m_scene;
50 //private IConfigSource m_config; // not used currently
51
52 public void Initialise(Scene scene, IConfigSource config)
53 {
54 m_scene = scene;
55 // m_config = config; // not used currently
56 }
57
58 public void TerrainToBitmap(Bitmap mapbmp)
59 {
60 int tc = System.Environment.TickCount;
61 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");
62
63 double[,] hm = m_scene.Heightmap.GetDoubles();
64 bool ShadowDebugContinue = true;
65
66 bool terraincorruptedwarningsaid = false;
67
68 float low = 255;
69 float high = 0;
70 for (int x = 0; x < 256; x++)
71 {
72 for (int y = 0; y < 256; y++)
73 {
74 float hmval = (float)hm[x, y];
75 if (hmval < low)
76 low = hmval;
77 if (hmval > high)
78 high = hmval;
79 }
80 }
81
82 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
83
84 for (int x = 0; x < 256; x++)
85 {
86 for (int y = 0; y < 256; y++)
87 {
88 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
89 int yr = 255 - y;
90
91 float heightvalue = (float)hm[x, y];
92
93 if (heightvalue > waterHeight)
94 {
95 // scale height value
96 // No, that doesn't scale it:
97 // heightvalue = low + mid * (heightvalue - low) / mid; => low + (heightvalue - low) * mid / mid = low + (heightvalue - low) * 1 = low + heightvalue - low = heightvalue
98
99 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
100 heightvalue = 0;
101 else if (heightvalue > 255f)
102 heightvalue = 255f;
103 else if (heightvalue < 0f)
104 heightvalue = 0f;
105
106 Color color = Color.FromArgb((int)heightvalue, 100, (int)heightvalue);
107
108 mapbmp.SetPixel(x, yr, color);
109
110 try
111 {
112 //X
113 // .
114 //
115 // Shade the terrain for shadows
116 if (x < 255 && yr < 255)
117 {
118 float hfvalue = (float)hm[x, y];
119 float hfvaluecompare = 0f;
120
121 if ((x + 1 < 256) && (y + 1 < 256))
122 {
123 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there
124 }
125 if (Single.IsInfinity(hfvalue) || Single.IsNaN(hfvalue))
126 hfvalue = 0f;
127
128 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
129 hfvaluecompare = 0f;
130
131 float hfdiff = hfvalue - hfvaluecompare; // => positive if NE is lower, negative if here is lower
132
133 int hfdiffi = 0;
134 int hfdiffihighlight = 0;
135 float highlightfactor = 0.18f;
136
137 try
138 {
139 // hfdiffi = Math.Abs((int)((hfdiff * 4) + (hfdiff * 0.5))) + 1;
140 hfdiffi = Math.Abs((int)(hfdiff * 4.5f)) + 1;
141 if (hfdiff % 1f != 0)
142 {
143 // hfdiffi = hfdiffi + Math.Abs((int)(((hfdiff % 1) * 0.5f) * 10f) - 1);
144 hfdiffi = hfdiffi + Math.Abs((int)((hfdiff % 1f) * 5f) - 1);
145 }
146
147 hfdiffihighlight = Math.Abs((int)((hfdiff * highlightfactor) * 4.5f)) + 1;
148 if (hfdiff % 1f != 0)
149 {
150 // hfdiffi = hfdiffi + Math.Abs((int)(((hfdiff % 1) * 0.5f) * 10f) - 1);
151 hfdiffihighlight = hfdiffihighlight + Math.Abs((int)(((hfdiff * highlightfactor) % 1f) * 5f) - 1);
152 }
153 }
154 catch (System.OverflowException)
155 {
156 m_log.Debug("[MAPTILE]: Shadow failed at value: " + hfdiff.ToString());
157 ShadowDebugContinue = false;
158 }
159
160 if (hfdiff > 0.3f)
161 {
162 // NE is lower than here
163 // We have to desaturate and lighten the land at the same time
164 // we use floats, colors use bytes, so shrink are space down to
165 // 0-255
166
167 if (ShadowDebugContinue)
168 {
169 int r = color.R;
170 int g = color.G;
171 int b = color.B;
172 color = Color.FromArgb((r + hfdiffihighlight < 255) ? r + hfdiffihighlight : 255,
173 (g + hfdiffihighlight < 255) ? g + hfdiffihighlight : 255,
174 (b + hfdiffihighlight < 255) ? b + hfdiffihighlight : 255);
175 }
176 }
177 else if (hfdiff < -0.3f)
178 {
179 // here is lower than NE:
180 // We have to desaturate and blacken the land at the same time
181 // we use floats, colors use bytes, so shrink are space down to
182 // 0-255
183
184 if (ShadowDebugContinue)
185 {
186 if ((x - 1 > 0) && (yr + 1 < 256))
187 {
188 color = mapbmp.GetPixel(x - 1, yr + 1);
189 int r = color.R;
190 int g = color.G;
191 int b = color.B;
192 color = Color.FromArgb((r - hfdiffi > 0) ? r - hfdiffi : 0,
193 (g - hfdiffi > 0) ? g - hfdiffi : 0,
194 (b - hfdiffi > 0) ? b - hfdiffi : 0);
195
196 mapbmp.SetPixel(x-1, yr+1, color);
197 }
198 }
199 }
200 }
201 }
202 catch (System.ArgumentException)
203 {
204 if (!terraincorruptedwarningsaid)
205 {
206 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
207 terraincorruptedwarningsaid = true;
208 }
209 color = Color.Black;
210 mapbmp.SetPixel(x, yr, color);
211 }
212 }
213 else
214 {
215 // We're under the water level with the terrain, so paint water instead of land
216
217 // Y flip the cordinates
218 heightvalue = waterHeight - heightvalue;
219 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
220 heightvalue = 0f;
221 else if (heightvalue > 19f)
222 heightvalue = 19f;
223 else if (heightvalue < 0f)
224 heightvalue = 0f;
225
226 heightvalue = 100f - (heightvalue * 100f) / 19f;
227
228 try
229 {
230 Color water = Color.FromArgb((int)heightvalue, (int)heightvalue, 255);
231 mapbmp.SetPixel(x, yr, water);
232 }
233 catch (System.ArgumentException)
234 {
235 if (!terraincorruptedwarningsaid)
236 {
237 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
238 terraincorruptedwarningsaid = true;
239 }
240 Color black = Color.Black;
241 mapbmp.SetPixel(x, (256 - y) - 1, black);
242 }
243 }
244 }
245 }
246 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms");
247 }
248 }
249}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs
new file mode 100644
index 0000000..537644a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs
@@ -0,0 +1,411 @@
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 OpenSim 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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Drawing2D;
33using System.Drawing.Imaging;
34using System.Reflection;
35using OpenMetaverse;
36using Nini.Config;
37using log4net;
38using OpenMetaverse.Imaging;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.CoreModules.World.Terrain;
43
44namespace OpenSim.Region.CoreModules.World.WorldMap
45{
46 // Hue, Saturation, Value; used for color-interpolation
47 struct HSV {
48 public float h;
49 public float s;
50 public float v;
51
52 public HSV(float h, float s, float v)
53 {
54 this.h = h;
55 this.s = s;
56 this.v = v;
57 }
58
59 // (for info about algorithm, see http://en.wikipedia.org/wiki/HSL_and_HSV)
60 public HSV(Color c)
61 {
62 float r = c.R / 255f;
63 float g = c.G / 255f;
64 float b = c.B / 255f;
65 float max = Math.Max(Math.Max(r, g), b);
66 float min = Math.Min(Math.Min(r, g), b);
67 float diff = max - min;
68
69 if (max == min) h = 0f;
70 else if (max == r) h = (g - b) / diff * 60f;
71 else if (max == g) h = (b - r) / diff * 60f + 120f;
72 else h = (r - g) / diff * 60f + 240f;
73 if (h < 0f) h += 360f;
74
75 if (max == 0f) s = 0f;
76 else s = diff / max;
77
78 v = max;
79 }
80
81 // (for info about algorithm, see http://en.wikipedia.org/wiki/HSL_and_HSV)
82 public Color toColor()
83 {
84 if (s < 0f) Console.WriteLine("S < 0: " + s);
85 else if (s > 1f) Console.WriteLine("S > 1: " + s);
86 if (v < 0f) Console.WriteLine("V < 0: " + v);
87 else if (v > 1f) Console.WriteLine("V > 1: " + v);
88
89 float f = h / 60f;
90 int sector = (int)f % 6;
91 f = f - (int)f;
92 int pi = (int)(v * (1f - s) * 255f);
93 int qi = (int)(v * (1f - s * f) * 255f);
94 int ti = (int)(v * (1f - (1f - f) * s) * 255f);
95 int vi = (int)(v * 255f);
96
97 switch (sector)
98 {
99 case 0:
100 return Color.FromArgb(vi, ti, pi);
101 case 1:
102 return Color.FromArgb(qi, vi, pi);
103 case 2:
104 return Color.FromArgb(pi, vi, ti);
105 case 3:
106 return Color.FromArgb(pi, qi, vi);
107 case 4:
108 return Color.FromArgb(ti, pi, vi);
109 default:
110 return Color.FromArgb(vi, pi, qi);
111 }
112 }
113 }
114
115 public class TexturedMapTileRenderer : IMapTileTerrainRenderer
116 {
117 #region Constants
118
119 private static readonly ILog m_log =
120 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
121
122 // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank").
123 // The color-values were choosen because they "look right" (at least to me) ;-)
124 private static readonly UUID defaultTerrainTexture1 = new UUID("0bc58228-74a0-7e83-89bc-5c23464bcec5");
125 private static readonly Color defaultColor1 = Color.FromArgb(165, 137, 118);
126 private static readonly UUID defaultTerrainTexture2 = new UUID("63338ede-0037-c4fd-855b-015d77112fc8");
127 private static readonly Color defaultColor2 = Color.FromArgb(69, 89, 49);
128 private static readonly UUID defaultTerrainTexture3 = new UUID("303cd381-8560-7579-23f1-f0a880799740");
129 private static readonly Color defaultColor3 = Color.FromArgb(162, 154, 141);
130 private static readonly UUID defaultTerrainTexture4 = new UUID("53a2f406-4895-1d13-d541-d2e3b86bc19c");
131 private static readonly Color defaultColor4 = Color.FromArgb(200, 200, 200);
132
133 #endregion
134
135
136 private Scene m_scene;
137 // private IConfigSource m_config; // not used currently
138
139 // mapping from texture UUIDs to averaged color. This will contain 5-9 values, in general; new values are only
140 // added when the terrain textures are changed in the estate dialog and a new map is generated (and will stay in
141 // that map until the region-server restarts. This could be considered a memory-leak, but it's a *very* small one.
142 // TODO does it make sense to use a "real" cache and regenerate missing entries on fetch?
143 private Dictionary<UUID, Color> m_mapping;
144
145
146 public void Initialise(Scene scene, IConfigSource source)
147 {
148 m_scene = scene;
149 // m_config = source; // not used currently
150 m_mapping = new Dictionary<UUID,Color>();
151 m_mapping.Add(defaultTerrainTexture1, defaultColor1);
152 m_mapping.Add(defaultTerrainTexture2, defaultColor2);
153 m_mapping.Add(defaultTerrainTexture3, defaultColor3);
154 m_mapping.Add(defaultTerrainTexture4, defaultColor4);
155 m_mapping.Add(Util.BLANK_TEXTURE_UUID, Color.White);
156 }
157
158 #region Helpers
159 // This fetches the texture from the asset server synchroneously. That should be ok, as we
160 // call map-creation only in those places:
161 // - on start: We can wait here until the asset server returns the texture
162 // TODO (- on "map" command: We are in the command-line thread, we will wait for completion anyway)
163 // TODO (- on "automatic" update after some change: We are called from the mapUpdateTimer here and
164 // will wait anyway)
165 private Bitmap fetchTexture(UUID id)
166 {
167 AssetBase asset = m_scene.AssetCache.GetAsset(id, true);
168 m_log.DebugFormat("Fetched texture {0}, found: {1}", id, asset != null);
169 if (asset == null) return null;
170
171 ManagedImage managedImage;
172 Image image;
173
174 try
175 {
176 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
177 return new Bitmap(image);
178 else
179 return null;
180 }
181 catch (DllNotFoundException)
182 {
183 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is emtpy for {0}", id);
184
185 }
186 catch (IndexOutOfRangeException)
187 {
188 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is emtpy for {0}", id);
189
190 }
191 catch (Exception)
192 {
193 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is emtpy for {0}", id);
194
195 }
196 return null;
197
198 }
199
200 // Compute the average color of a texture.
201 private Color computeAverageColor(Bitmap bmp)
202 {
203 // we have 256 x 256 pixel, each with 256 possible color-values per
204 // color-channel, so 2^24 is the maximum value we can get, adding everything.
205 // int is be big enough for that.
206 int r = 0, g = 0, b = 0;
207 for (int y = 0; y < bmp.Height; ++y)
208 {
209 for (int x = 0; x < bmp.Width; ++x)
210 {
211 Color c = bmp.GetPixel(x, y);
212 r += (int)c.R & 0xff;
213 g += (int)c.G & 0xff;
214 b += (int)c.B & 0xff;
215 }
216 }
217
218 int pixels = bmp.Width * bmp.Height;
219 return Color.FromArgb(r / pixels, g / pixels, b / pixels);
220 }
221
222 // return either the average color of the texture, or the defaultColor if the texturID is invalid
223 // or the texture couldn't be found
224 private Color computeAverageColor(UUID textureID, Color defaultColor) {
225 if (textureID == UUID.Zero) return defaultColor; // not set
226 if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures
227
228 Bitmap bmp = fetchTexture(textureID);
229 Color color = bmp == null ? defaultColor : computeAverageColor(bmp);
230 // store it for future reference
231 m_mapping[textureID] = color;
232
233 return color;
234 }
235
236 // S-curve: f(x) = 3x² - 2x³:
237 // f(0) = 0, f(0.5) = 0.5, f(1) = 1,
238 // f'(x) = 0 at x = 0 and x = 1; f'(0.5) = 1.5,
239 // f''(0.5) = 0, f''(x) != 0 for x != 0.5
240 private float S(float v) {
241 return (v * v * (3f - 2f * v));
242 }
243
244 // interpolate two colors in HSV space and return the resulting color
245 private HSV interpolateHSV(ref HSV c1, ref HSV c2, float ratio) {
246 if (ratio <= 0f) return c1;
247 if (ratio >= 1f) return c2;
248
249 // make sure we are on the same side on the hue-circle for interpolation
250 // We change the hue of the parameters here, but we don't change the color
251 // represented by that value
252 if (c1.h - c2.h > 180f) c1.h -= 360f;
253 else if (c2.h - c1.h > 180f) c1.h += 360f;
254
255 return new HSV(c1.h * (1f - ratio) + c2.h * ratio,
256 c1.s * (1f - ratio) + c2.s * ratio,
257 c1.v * (1f - ratio) + c2.v * ratio);
258 }
259
260 // the heigthfield might have some jumps in values. Rendered land is smooth, though,
261 // as a slope is rendered at that place. So average 4 neighbour values to emulate that.
262 private float getHeight(double[,] hm, int x, int y) {
263 if (x < 255 && y < 255)
264 return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112);
265 else
266 return (float)hm[x, y];
267 }
268 #endregion
269
270 public void TerrainToBitmap(Bitmap mapbmp)
271 {
272 int tc = System.Environment.TickCount;
273 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");
274
275 // These textures should be in the AssetCache anyway, as every client conneting to this
276 // region needs them. Except on start, when the map is recreated (before anyone connected),
277 // and on change of the estate settings (textures and terrain values), when the map should
278 // be recreated.
279 RegionSettings settings = m_scene.RegionInfo.RegionSettings;
280
281 // the four terrain colors as HSVs for interpolation
282 HSV hsv1 = new HSV(computeAverageColor(settings.TerrainTexture1, defaultColor1));
283 HSV hsv2 = new HSV(computeAverageColor(settings.TerrainTexture2, defaultColor2));
284 HSV hsv3 = new HSV(computeAverageColor(settings.TerrainTexture3, defaultColor3));
285 HSV hsv4 = new HSV(computeAverageColor(settings.TerrainTexture4, defaultColor4));
286
287 float levelNElow = (float)settings.Elevation1NE;
288 float levelNEhigh = (float)settings.Elevation2NE;
289
290 float levelNWlow = (float)settings.Elevation1NW;
291 float levelNWhigh = (float)settings.Elevation2NW;
292
293 float levelSElow = (float)settings.Elevation1SE;
294 float levelSEhigh = (float)settings.Elevation2SE;
295
296 float levelSWlow = (float)settings.Elevation1SW;
297 float levelSWhigh = (float)settings.Elevation2SW;
298
299 float waterHeight = (float)settings.WaterHeight;
300
301 double[,] hm = m_scene.Heightmap.GetDoubles();
302
303 for (int x = 0; x < 256; x++)
304 {
305 float columnRatio = x / 255f; // 0 - 1, for interpolation
306 for (int y = 0; y < 256; y++)
307 {
308 float rowRatio = y / 255f; // 0 - 1, for interpolation
309
310 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
311 int yr = 255 - y;
312
313 float heightvalue = getHeight(hm, x, y);
314 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
315 heightvalue = 0;
316
317 if (heightvalue > waterHeight)
318 {
319 // add a bit noise for breaking up those flat colors:
320 // - a large-scale noise, for the "patches" (using an doubled s-curve for sharper contrast)
321 // - a small-scale noise, for bringing in some small scale variation
322 //float bigNoise = (float)TerrainUtil.InterpolatedNoise(x / 8.0, y / 8.0) * .5f + .5f; // map to 0.0 - 1.0
323 //float smallNoise = (float)TerrainUtil.InterpolatedNoise(x + 33, y + 43) * .5f + .5f;
324 //float hmod = heightvalue + smallNoise * 3f + S(S(bigNoise)) * 10f;
325 float hmod =
326 heightvalue +
327 (float)TerrainUtil.InterpolatedNoise(x + 33, y + 43) * 1.5f + 1.5f + // 0 - 3
328 S(S((float)TerrainUtil.InterpolatedNoise(x / 8.0, y / 8.0) * .5f + .5f)) * 10f; // 0 - 10
329
330 // find the low/high values for this point (interpolated bilinearily)
331 // (and remember, x=0,y=0 is SW)
332 float low = levelSWlow * (1f - rowRatio) * (1f - columnRatio) +
333 levelSElow * (1f - rowRatio) * columnRatio +
334 levelNWlow * rowRatio * (1f - columnRatio) +
335 levelNElow * rowRatio * columnRatio;
336 float high = levelSWhigh * (1f - rowRatio) * (1f - columnRatio) +
337 levelSEhigh * (1f - rowRatio) * columnRatio +
338 levelNWhigh * rowRatio * (1f - columnRatio) +
339 levelNEhigh * rowRatio * columnRatio;
340 if (high < low)
341 {
342 // someone tried to fool us. High value should be higher than low every time
343 float tmp = high;
344 high = low;
345 low = tmp;
346 }
347
348 HSV hsv;
349 if (hmod <= low) hsv = hsv1; // too low
350 else if (hmod >= high) hsv = hsv4; // too high
351 else
352 {
353 // HSV-interpolate along the colors
354 // first, rescale h to 0.0 - 1.0
355 hmod = (hmod - low) / (high - low);
356 // now we have to split: 0.00 => color1, 0.33 => color2, 0.67 => color3, 1.00 => color4
357 if (hmod < 1f/3f) hsv = interpolateHSV(ref hsv1, ref hsv2, hmod * 3f);
358 else if (hmod < 2f/3f) hsv = interpolateHSV(ref hsv2, ref hsv3, (hmod * 3f) - 1f);
359 else hsv = interpolateHSV(ref hsv3, ref hsv4, (hmod * 3f) - 2f);
360 }
361
362 // Shade the terrain for shadows
363 if (x < 255 && y < 255)
364 {
365 float hfvaluecompare = getHeight(hm, x + 1, y + 1); // light from north-east => look at land height there
366 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
367 hfvaluecompare = 0f;
368
369 float hfdiff = heightvalue - hfvaluecompare; // => positive if NE is lower, negative if here is lower
370 hfdiff *= 0.06f; // some random factor so "it looks good"
371 if (hfdiff > 0.02f)
372 {
373 float highlightfactor = 0.18f;
374 // NE is lower than here
375 // We have to desaturate and lighten the land at the same time
376 hsv.s = (hsv.s - (hfdiff * highlightfactor) > 0f) ? hsv.s - (hfdiff * highlightfactor) : 0f;
377 hsv.v = (hsv.v + (hfdiff * highlightfactor) < 1f) ? hsv.v + (hfdiff * highlightfactor) : 1f;
378 }
379 else if (hfdiff < -0.02f)
380 {
381 // here is lower than NE:
382 // We have to desaturate and blacken the land at the same time
383 hsv.s = (hsv.s + hfdiff > 0f) ? hsv.s + hfdiff : 0f;
384 hsv.v = (hsv.v + hfdiff > 0f) ? hsv.v + hfdiff : 0f;
385 }
386 }
387 mapbmp.SetPixel(x, yr, hsv.toColor());
388 }
389 else
390 {
391 // We're under the water level with the terrain, so paint water instead of land
392
393 heightvalue = waterHeight - heightvalue;
394 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
395 heightvalue = 0f;
396 else if (heightvalue > 19f)
397 heightvalue = 19f;
398 else if (heightvalue < 0f)
399 heightvalue = 0f;
400
401 heightvalue = 100f - (heightvalue * 100f) / 19f; // 0 - 19 => 100 - 0
402
403 Color water = Color.FromArgb((int)heightvalue, (int)heightvalue, 255);
404 mapbmp.SetPixel(x, yr, water);
405 }
406 }
407 }
408 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms");
409 }
410 }
411}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
new file mode 100644
index 0000000..376e365
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -0,0 +1,905 @@
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 OpenSim 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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.IO;
34using System.Net;
35using System.Reflection;
36using System.Threading;
37using OpenMetaverse;
38using OpenMetaverse.Imaging;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using OpenSim.Framework;
43using OpenSim.Framework.Communications.Cache;
44using OpenSim.Framework.Communications.Capabilities;
45using OpenSim.Framework.Servers;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Framework.Scenes.Types;
49using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
50
51using OSD = OpenMetaverse.StructuredData.OSD;
52using OSDMap = OpenMetaverse.StructuredData.OSDMap;
53using OSDArray = OpenMetaverse.StructuredData.OSDArray;
54
55namespace OpenSim.Region.CoreModules.World.WorldMap
56{
57 public class WorldMapModule : IRegionModule
58 {
59 private static readonly ILog m_log =
60 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
62 private static readonly string m_mapLayerPath = "0001/";
63
64 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
65
66 //private IConfig m_config;
67 protected Scene m_scene;
68 private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
69 private int cachedTime = 0;
70 private byte[] myMapImageJPEG;
71 protected 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 Thread mapItemReqThread;
78 private volatile bool threadrunning = false;
79
80 //private int CacheRegionsDistance = 256;
81
82 #region IRegionModule Members
83
84 public virtual void Initialise(Scene scene, IConfigSource config)
85 {
86 IConfig startupConfig = config.Configs["Startup"];
87 if (startupConfig.GetString("WorldMapModule", "WorldMap") ==
88 "WorldMap")
89 m_Enabled = true;
90
91 if (!m_Enabled)
92 return;
93
94 m_scene = scene;
95 }
96
97 public virtual void PostInitialise()
98 {
99 if (m_Enabled)
100 AddHandlers();
101 }
102
103 public virtual void Close()
104 {
105 }
106
107 public virtual string Name
108 {
109 get { return "WorldMapModule"; }
110 }
111
112 public bool IsSharedModule
113 {
114 get { return false; }
115 }
116
117 #endregion
118
119 protected virtual void AddHandlers()
120 {
121 myMapImageJPEG = new byte[0];
122
123 string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString();
124 regionimage = regionimage.Replace("-", "");
125 m_log.Info("[WORLD MAP]: JPEG Map location: http://" + m_scene.RegionInfo.ExternalEndPoint.Address.ToString() + ":" + m_scene.RegionInfo.HttpPort.ToString() + "/index.php?method=" + regionimage);
126
127 m_scene.CommsManager.HttpServer.AddHTTPHandler(regionimage, OnHTTPGetMapImage);
128 m_scene.CommsManager.HttpServer.AddLLSDHandler(
129 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
130
131 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
132 m_scene.EventManager.OnNewClient += OnNewClient;
133 m_scene.EventManager.OnClientClosed += ClientLoggedOut;
134 m_scene.EventManager.OnMakeChildAgent += MakeChildAgent;
135 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
136 }
137
138 public void OnRegisterCaps(UUID agentID, Caps caps)
139 {
140 //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
141 string capsBase = "/CAPS/" + caps.CapsObjectPath;
142 caps.RegisterHandler("MapLayer",
143 new RestStreamHandler("POST", capsBase + m_mapLayerPath,
144 delegate(string request, string path, string param,
145 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
146 {
147 return MapLayerRequest(request, path, param,
148 agentID, caps);
149 }));
150 }
151
152 /// <summary>
153 /// Callback for a map layer request
154 /// </summary>
155 /// <param name="request"></param>
156 /// <param name="path"></param>
157 /// <param name="param"></param>
158 /// <param name="agentID"></param>
159 /// <param name="caps"></param>
160 /// <returns></returns>
161 public string MapLayerRequest(string request, string path, string param,
162 UUID agentID, Caps caps)
163 {
164 //try
165 //{
166 //m_log.DebugFormat("[MAPLAYER]: request: {0}, path: {1}, param: {2}, agent:{3}",
167 //request, path, param,agentID.ToString());
168
169 // this is here because CAPS map requests work even beyond the 10,000 limit.
170 ScenePresence avatarPresence = null;
171
172 m_scene.TryGetAvatar(agentID, out avatarPresence);
173
174 if (avatarPresence != null)
175 {
176 bool lookup = false;
177
178 lock (cachedMapBlocks)
179 {
180 if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch()))
181 {
182 List<MapBlockData> mapBlocks;
183
184 mapBlocks = cachedMapBlocks;
185 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
186 }
187 else
188 {
189 lookup = true;
190 }
191 }
192 if (lookup)
193 {
194 List<MapBlockData> mapBlocks;
195
196 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks((int)m_scene.RegionInfo.RegionLocX - 8, (int)m_scene.RegionInfo.RegionLocY - 8, (int)m_scene.RegionInfo.RegionLocX + 8, (int)m_scene.RegionInfo.RegionLocY + 8);
197 avatarPresence.ControllingClient.SendMapBlock(mapBlocks,0);
198
199 lock (cachedMapBlocks)
200 cachedMapBlocks = mapBlocks;
201
202 cachedTime = Util.UnixTimeSinceEpoch();
203 }
204 }
205 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
206 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
207 return mapResponse.ToString();
208 }
209
210 /// <summary>
211 ///
212 /// </summary>
213 /// <param name="mapReq"></param>
214 /// <returns></returns>
215 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
216 {
217 m_log.Debug("[WORLD MAP]: MapLayer Request in region: " + m_scene.RegionInfo.RegionName);
218 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
219 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
220 return mapResponse;
221 }
222
223 /// <summary>
224 ///
225 /// </summary>
226 /// <returns></returns>
227 protected static OSDMapLayer GetOSDMapLayerResponse()
228 {
229 OSDMapLayer mapLayer = new OSDMapLayer();
230 mapLayer.Right = 5000;
231 mapLayer.Top = 5000;
232 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
233
234 return mapLayer;
235 }
236 #region EventHandlers
237
238 /// <summary>
239 /// Registered for event
240 /// </summary>
241 /// <param name="client"></param>
242 private void OnNewClient(IClientAPI client)
243 {
244 client.OnRequestMapBlocks += RequestMapBlocks;
245 client.OnMapItemRequest += HandleMapItemRequest;
246 }
247
248 /// <summary>
249 /// Client logged out, check to see if there are any more root agents in the simulator
250 /// If not, stop the mapItemRequest Thread
251 /// Event handler
252 /// </summary>
253 /// <param name="AgentId">AgentID that logged out</param>
254 private void ClientLoggedOut(UUID AgentId)
255 {
256 List<ScenePresence> presences = m_scene.GetAvatars();
257 int rootcount = 0;
258 for (int i=0;i<presences.Count;i++)
259 {
260 if (presences[i] != null)
261 {
262 if (!presences[i].IsChildAgent)
263 rootcount++;
264 }
265 }
266 if (rootcount <= 1)
267 StopThread();
268
269 lock (m_rootAgents)
270 {
271 if (m_rootAgents.Contains(AgentId))
272 {
273 m_rootAgents.Remove(AgentId);
274 }
275 }
276 }
277 #endregion
278
279 /// <summary>
280 /// Starts the MapItemRequest Thread
281 /// Note that this only gets started when there are actually agents in the region
282 /// Additionally, it gets stopped when there are none.
283 /// </summary>
284 /// <param name="o"></param>
285 private void StartThread(object o)
286 {
287 if (threadrunning) return;
288 threadrunning = true;
289 m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread");
290 mapItemReqThread = new Thread(new ThreadStart(process));
291 mapItemReqThread.IsBackground = true;
292 mapItemReqThread.Name = "MapItemRequestThread";
293 mapItemReqThread.Priority = ThreadPriority.BelowNormal;
294 mapItemReqThread.SetApartmentState(ApartmentState.MTA);
295 mapItemReqThread.Start();
296 ThreadTracker.Add(mapItemReqThread);
297 }
298
299 /// <summary>
300 /// Enqueues a 'stop thread' MapRequestState. Causes the MapItemRequest thread to end
301 /// </summary>
302 private void StopThread()
303 {
304 MapRequestState st = new MapRequestState();
305 st.agentID=UUID.Zero;
306 st.EstateID=0;
307 st.flags=0;
308 st.godlike=false;
309 st.itemtype=0;
310 st.regionhandle=0;
311
312 requests.Enqueue(st);
313 }
314
315 public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
316 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
317 {
318 lock (m_rootAgents)
319 {
320 if (!m_rootAgents.Contains(remoteClient.AgentId))
321 return;
322 }
323 uint xstart = 0;
324 uint ystart = 0;
325 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
326 if (itemtype == 6) // we only sevice 6 right now (avatar green dots)
327 {
328 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
329 {
330 // Local Map Item Request
331 List<ScenePresence> avatars = m_scene.GetAvatars();
332 int tc = System.Environment.TickCount;
333 List<mapItemReply> mapitems = new List<mapItemReply>();
334 mapItemReply mapitem = new mapItemReply();
335 if (avatars.Count == 0 || avatars.Count == 1)
336 {
337 mapitem = new mapItemReply();
338 mapitem.x = (uint)(xstart + 1);
339 mapitem.y = (uint)(ystart + 1);
340 mapitem.id = UUID.Zero;
341 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
342 mapitem.Extra = 0;
343 mapitem.Extra2 = 0;
344 mapitems.Add(mapitem);
345 }
346 else
347 {
348 foreach (ScenePresence av in avatars)
349 {
350 // Don't send a green dot for yourself
351 if (av.UUID != remoteClient.AgentId)
352 {
353 mapitem = new mapItemReply();
354 mapitem.x = (uint)(xstart + av.AbsolutePosition.X);
355 mapitem.y = (uint)(ystart + av.AbsolutePosition.Y);
356 mapitem.id = UUID.Zero;
357 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
358 mapitem.Extra = 1;
359 mapitem.Extra2 = 0;
360 mapitems.Add(mapitem);
361 }
362 }
363 }
364 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
365 }
366 else
367 {
368 // Remote Map Item Request
369
370 // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes.
371 // Note that we only start up a remote mapItem Request thread if there's users who could
372 // be making requests
373 if (!threadrunning)
374 {
375 m_log.Warn("[WORLD MAP]: Starting new remote request thread manually. This means that AvatarEnteringParcel never fired! This needs to be fixed! Don't Mantis this, as the developers can see it in this message");
376 StartThread(new object());
377 }
378
379 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
380 }
381 }
382 }
383
384 /// <summary>
385 /// Processing thread main() loop for doing remote mapitem requests
386 /// </summary>
387 public void process()
388 {
389 try
390 {
391 while (true)
392 {
393 MapRequestState st = requests.Dequeue();
394
395 // end gracefully
396 if (st.agentID == UUID.Zero)
397 {
398 ThreadTracker.Remove(mapItemReqThread);
399 break;
400 }
401
402 bool dorequest = true;
403 lock (m_rootAgents)
404 {
405 if (!m_rootAgents.Contains(st.agentID))
406 dorequest = false;
407 }
408
409 if (dorequest)
410 {
411 OSDMap response = RequestMapItemsAsync("", st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
412 RequestMapItemsCompleted(response);
413 }
414 }
415 }
416 catch (Exception e)
417 {
418 m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e);
419 }
420
421 threadrunning = false;
422 }
423
424 /// <summary>
425 /// Enqueues the map item request into the processing thread
426 /// </summary>
427 /// <param name="state"></param>
428 public void EnqueueMapItemRequest(MapRequestState state)
429 {
430 requests.Enqueue(state);
431 }
432
433 /// <summary>
434 /// Sends the mapitem response to the IClientAPI
435 /// </summary>
436 /// <param name="response">The OSDMap Response for the mapitem</param>
437 private void RequestMapItemsCompleted(OSDMap response)
438 {
439 UUID requestID = response["requestID"].AsUUID();
440
441 if (requestID != UUID.Zero)
442 {
443 MapRequestState mrs = new MapRequestState();
444 mrs.agentID = UUID.Zero;
445 lock (m_openRequests)
446 {
447 if (m_openRequests.ContainsKey(requestID))
448 {
449 mrs = m_openRequests[requestID];
450 m_openRequests.Remove(requestID);
451 }
452 }
453
454 if (mrs.agentID != UUID.Zero)
455 {
456 ScenePresence av = null;
457 m_scene.TryGetAvatar(mrs.agentID, out av);
458 if (av != null)
459 {
460 if (response.ContainsKey(mrs.itemtype.ToString()))
461 {
462 List<mapItemReply> returnitems = new List<mapItemReply>();
463 OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()];
464 for (int i = 0; i < itemarray.Count; i++)
465 {
466 OSDMap mapitem = (OSDMap)itemarray[i];
467 mapItemReply mi = new mapItemReply();
468 mi.x = (uint)mapitem["X"].AsInteger();
469 mi.y = (uint)mapitem["Y"].AsInteger();
470 mi.id = mapitem["ID"].AsUUID();
471 mi.Extra = mapitem["Extra"].AsInteger();
472 mi.Extra2 = mapitem["Extra2"].AsInteger();
473 mi.name = mapitem["Name"].AsString();
474 returnitems.Add(mi);
475 }
476 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
477 }
478 }
479 }
480 }
481 }
482
483 /// <summary>
484 /// Enqueue the MapItem request for remote processing
485 /// </summary>
486 /// <param name="httpserver">blank string, we discover this in the process</param>
487 /// <param name="id">Agent ID that we are making this request on behalf</param>
488 /// <param name="flags">passed in from packet</param>
489 /// <param name="EstateID">passed in from packet</param>
490 /// <param name="godlike">passed in from packet</param>
491 /// <param name="itemtype">passed in from packet</param>
492 /// <param name="regionhandle">Region we're looking up</param>
493 public void RequestMapItems(string httpserver, UUID id, uint flags,
494 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
495 {
496 MapRequestState st = new MapRequestState();
497 st.agentID = id;
498 st.flags = flags;
499 st.EstateID = EstateID;
500 st.godlike = godlike;
501 st.itemtype = itemtype;
502 st.regionhandle = regionhandle;
503 EnqueueMapItemRequest(st);
504 }
505
506 /// <summary>
507 /// Does the actual remote mapitem request
508 /// This should be called from an asynchronous thread
509 /// Request failures get blacklisted until region restart so we don't
510 /// continue to spend resources trying to contact regions that are down.
511 /// </summary>
512 /// <param name="httpserver">blank string, we discover this in the process</param>
513 /// <param name="id">Agent ID that we are making this request on behalf</param>
514 /// <param name="flags">passed in from packet</param>
515 /// <param name="EstateID">passed in from packet</param>
516 /// <param name="godlike">passed in from packet</param>
517 /// <param name="itemtype">passed in from packet</param>
518 /// <param name="regionhandle">Region we're looking up</param>
519 /// <returns></returns>
520 private OSDMap RequestMapItemsAsync(string httpserver, UUID id, uint flags,
521 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
522 {
523 bool blacklisted = false;
524 lock (m_blacklistedregions)
525 {
526 if (m_blacklistedregions.ContainsKey(regionhandle))
527 blacklisted = true;
528 }
529
530 if (blacklisted)
531 return new OSDMap();
532
533 UUID requestID = UUID.Random();
534 lock (m_cachedRegionMapItemsAddress)
535 {
536 if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
537 httpserver = m_cachedRegionMapItemsAddress[regionhandle];
538 }
539 if (httpserver.Length == 0)
540 {
541 RegionInfo mreg = m_scene.SceneGridService.RequestNeighbouringRegionInfo(regionhandle);
542
543 if (mreg != null)
544 {
545 httpserver = "http://" + mreg.ExternalEndPoint.Address.ToString() + ":" + mreg.HttpPort + "/MAP/MapItems/" + regionhandle.ToString();
546 lock (m_cachedRegionMapItemsAddress)
547 {
548 if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
549 m_cachedRegionMapItemsAddress.Add(regionhandle, httpserver);
550 }
551 }
552 else
553 {
554 lock (m_blacklistedregions)
555 {
556 if (!m_blacklistedregions.ContainsKey(regionhandle))
557 m_blacklistedregions.Add(regionhandle, System.Environment.TickCount);
558 }
559 m_log.InfoFormat("[WORLD MAP]: Blacklisted region {0}", regionhandle.ToString());
560 }
561 }
562
563 blacklisted = false;
564 lock (m_blacklistedurls)
565 {
566 if (m_blacklistedurls.ContainsKey(httpserver))
567 blacklisted = true;
568 }
569
570 // Can't find the http server
571 if (httpserver.Length == 0 || blacklisted)
572 return new OSDMap();
573
574 MapRequestState mrs = new MapRequestState();
575 mrs.agentID = id;
576 mrs.EstateID = EstateID;
577 mrs.flags = flags;
578 mrs.godlike = godlike;
579 mrs.itemtype=itemtype;
580 mrs.regionhandle = regionhandle;
581
582 lock (m_openRequests)
583 m_openRequests.Add(requestID, mrs);
584
585 WebRequest mapitemsrequest = WebRequest.Create(httpserver);
586 mapitemsrequest.Method = "POST";
587 mapitemsrequest.ContentType = "application/xml+llsd";
588 OSDMap RAMap = new OSDMap();
589
590 // string RAMapString = RAMap.ToString();
591 OSD LLSDofRAMap = RAMap; // RENAME if this works
592
593 byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap);
594 OSDMap responseMap = new OSDMap();
595 responseMap["requestID"] = OSD.FromUUID(requestID);
596
597 Stream os = null;
598 try
599 { // send the Post
600 mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send
601 os = mapitemsrequest.GetRequestStream();
602 os.Write(buffer, 0, buffer.Length); //Send it
603 os.Close();
604 //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from Sim {0}", httpserver);
605 }
606 catch (WebException ex)
607 {
608 m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
609 responseMap["connect"] = OSD.FromBoolean(false);
610 lock (m_blacklistedurls)
611 {
612 if (!m_blacklistedurls.ContainsKey(httpserver))
613 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
614 }
615
616 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
617
618 return responseMap;
619 }
620
621 string response_mapItems_reply = null;
622 { // get the response
623 try
624 {
625 WebResponse webResponse = mapitemsrequest.GetResponse();
626 if (webResponse != null)
627 {
628 StreamReader sr = new StreamReader(webResponse.GetResponseStream());
629 response_mapItems_reply = sr.ReadToEnd().Trim();
630 }
631 else
632 {
633 return new OSDMap();
634 }
635 }
636 catch (WebException)
637 {
638 responseMap["connect"] = OSD.FromBoolean(false);
639 lock (m_blacklistedurls)
640 {
641 if (!m_blacklistedurls.ContainsKey(httpserver))
642 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
643 }
644
645 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
646
647 return responseMap;
648 }
649 OSD rezResponse = null;
650 try
651 {
652 rezResponse = OSDParser.DeserializeLLSDXml(response_mapItems_reply);
653
654 responseMap = (OSDMap)rezResponse;
655 responseMap["requestID"] = OSD.FromUUID(requestID);
656 }
657 catch (Exception)
658 {
659 //m_log.InfoFormat("[OGP]: exception on parse of rez reply {0}", ex.Message);
660 responseMap["connect"] = OSD.FromBoolean(false);
661
662 return responseMap;
663 }
664 }
665 return responseMap;
666 }
667
668 /// <summary>
669 /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates
670 /// </summary>
671 /// <param name="minX"></param>
672 /// <param name="minY"></param>
673 /// <param name="maxX"></param>
674 /// <param name="maxY"></param>
675 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
676 {
677 List<MapBlockData> mapBlocks;
678 if ((flag & 0x10000) != 0) // user clicked on the map a tile that isn't visible
679 {
680 List<MapBlockData> response = new List<MapBlockData>();
681
682 // this should return one mapblock at most. But make sure: Look whether the one we requested is in there
683 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY);
684 if (mapBlocks != null)
685 {
686 foreach (MapBlockData block in mapBlocks)
687 {
688 if (block.X == minX && block.Y == minY)
689 {
690 // found it => add it to response
691 response.Add(block);
692 break;
693 }
694 }
695 }
696
697 if (response.Count == 0)
698 {
699 // response still empty => couldn't find the map-tile the user clicked on => tell the client
700 MapBlockData block = new MapBlockData();
701 block.X = (ushort)minX;
702 block.Y = (ushort)minY;
703 block.Access = 254; // == not there
704 response.Add(block);
705 }
706 remoteClient.SendMapBlock(response, 0);
707 }
708 else
709 {
710 // normal mapblock request. Use the provided values
711 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX - 4, minY - 4, maxX + 4, maxY + 4);
712 remoteClient.SendMapBlock(mapBlocks, flag);
713 }
714 }
715
716 public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
717 {
718 m_log.Debug("[WORLD MAP]: Sending map image jpeg");
719 Hashtable reply = new Hashtable();
720 int statuscode = 200;
721 byte[] jpeg = new byte[0];
722
723 if (myMapImageJPEG.Length == 0)
724 {
725 MemoryStream imgstream = new MemoryStream();
726 Bitmap mapTexture = new Bitmap(1,1);
727 ManagedImage managedImage;
728 Image image = (Image)mapTexture;
729
730 try
731 {
732 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data
733
734 imgstream = new MemoryStream();
735
736 // non-async because we know we have the asset immediately.
737 AssetBase mapasset = m_scene.AssetCache.GetAsset(m_scene.RegionInfo.lastMapUUID, true);
738
739 // Decode image to System.Drawing.Image
740 if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image))
741 {
742 // Save to bitmap
743 mapTexture = new Bitmap(image);
744
745 EncoderParameters myEncoderParameters = new EncoderParameters();
746 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L);
747
748 // Save bitmap to stream
749 mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters);
750
751 // Write the stream to a byte array for output
752 jpeg = imgstream.ToArray();
753 myMapImageJPEG = jpeg;
754 }
755 }
756 catch (Exception)
757 {
758 // Dummy!
759 m_log.Warn("[WORLD MAP]: Unable to generate Map image");
760 }
761 finally
762 {
763 // Reclaim memory, these are unmanaged resources
764 mapTexture.Dispose();
765 image.Dispose();
766 imgstream.Close();
767 imgstream.Dispose();
768 }
769 }
770 else
771 {
772 // Use cached version so we don't have to loose our mind
773 jpeg = myMapImageJPEG;
774 }
775
776 reply["str_response_string"] = Convert.ToBase64String(jpeg);
777 reply["int_response_code"] = statuscode;
778 reply["content_type"] = "image/jpeg";
779
780 return reply;
781 }
782
783 // From msdn
784 private static ImageCodecInfo GetEncoderInfo(String mimeType)
785 {
786 ImageCodecInfo[] encoders;
787 encoders = ImageCodecInfo.GetImageEncoders();
788 for (int j = 0; j < encoders.Length; ++j)
789 {
790 if (encoders[j].MimeType == mimeType)
791 return encoders[j];
792 }
793 return null;
794 }
795
796 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
797 {
798 uint xstart = 0;
799 uint ystart = 0;
800
801 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
802
803 OSDMap responsemap = new OSDMap();
804 List<ScenePresence> avatars = m_scene.GetAvatars();
805 OSDArray responsearr = new OSDArray(avatars.Count);
806 OSDMap responsemapdata = new OSDMap();
807 int tc = System.Environment.TickCount;
808 /*
809 foreach (ScenePresence av in avatars)
810 {
811 responsemapdata = new OSDMap();
812 responsemapdata["X"] = OSD.FromInteger((int)(xstart + av.AbsolutePosition.X));
813 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + av.AbsolutePosition.Y));
814 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
815 responsemapdata["Name"] = OSD.FromString("TH");
816 responsemapdata["Extra"] = OSD.FromInteger(0);
817 responsemapdata["Extra2"] = OSD.FromInteger(0);
818 responsearr.Add(responsemapdata);
819 }
820 responsemap["1"] = responsearr;
821 */
822 if (avatars.Count == 0)
823 {
824 responsemapdata = new OSDMap();
825 responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1));
826 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1));
827 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
828 responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
829 responsemapdata["Extra"] = OSD.FromInteger(0);
830 responsemapdata["Extra2"] = OSD.FromInteger(0);
831 responsearr.Add(responsemapdata);
832
833 responsemap["6"] = responsearr;
834 }
835 else
836 {
837 responsearr = new OSDArray(avatars.Count);
838 foreach (ScenePresence av in avatars)
839 {
840 responsemapdata = new OSDMap();
841 responsemapdata["X"] = OSD.FromInteger((int)(xstart + av.AbsolutePosition.X));
842 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + av.AbsolutePosition.Y));
843 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
844 responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
845 responsemapdata["Extra"] = OSD.FromInteger(1);
846 responsemapdata["Extra2"] = OSD.FromInteger(0);
847 responsearr.Add(responsemapdata);
848 }
849 responsemap["6"] = responsearr;
850 }
851 return responsemap;
852 }
853
854 private void MakeRootAgent(ScenePresence avatar)
855 {
856 // You may ask, why this is in a threadpool to start with..
857 // The reason is so we don't cause the thread to freeze waiting
858 // for the 1 second it costs to start a thread manually.
859 if (!threadrunning)
860 ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartThread));
861
862 lock (m_rootAgents)
863 {
864 if (!m_rootAgents.Contains(avatar.UUID))
865 {
866 m_rootAgents.Add(avatar.UUID);
867 }
868 }
869 }
870
871 private void MakeChildAgent(ScenePresence avatar)
872 {
873 List<ScenePresence> presences = m_scene.GetAvatars();
874 int rootcount = 0;
875 for (int i = 0; i < presences.Count; i++)
876 {
877 if (presences[i] != null)
878 {
879 if (!presences[i].IsChildAgent)
880 rootcount++;
881 }
882 }
883 if (rootcount <= 1)
884 StopThread();
885
886 lock (m_rootAgents)
887 {
888 if (m_rootAgents.Contains(avatar.UUID))
889 {
890 m_rootAgents.Remove(avatar.UUID);
891 }
892 }
893 }
894 }
895
896 public struct MapRequestState
897 {
898 public UUID agentID;
899 public uint flags;
900 public uint EstateID;
901 public bool godlike;
902 public uint itemtype;
903 public ulong regionhandle;
904 }
905}