aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/CoreModules/World
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/CoreModules/World')
-rw-r--r--OpenSim/Region/CoreModules/World/Access/AccessModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs314
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs84
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs109
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs9
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs23
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs45
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs519
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs218
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs255
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs288
-rw-r--r--OpenSim/Region/CoreModules/World/Land/DwellModule.cs22
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandChannel.cs5
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs938
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs324
-rw-r--r--OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs11
-rw-r--r--OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs266
-rw-r--r--OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs694
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs41
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs64
-rw-r--r--OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs7
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs21
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs153
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs160
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RestartModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs30
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs556
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs9
-rw-r--r--OpenSim/Region/CoreModules/World/Sun/SunModule.cs225
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs235
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs13
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs49
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs60
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs77
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs93
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs108
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs131
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs378
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs17
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs814
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs75
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs436
-rw-r--r--OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs260
-rw-r--r--OpenSim/Region/CoreModules/World/Wind/WindModule.cs38
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs94
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs517
61 files changed, 7061 insertions, 2257 deletions
diff --git a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
index 1599f15..f567cab 100644
--- a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
+++ b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
@@ -91,13 +91,17 @@ namespace OpenSim.Region.CoreModules.World
91 91
92 public void AddRegion(Scene scene) 92 public void AddRegion(Scene scene)
93 { 93 {
94 if (!m_SceneList.Contains(scene)) 94 lock (m_SceneList)
95 m_SceneList.Add(scene); 95 {
96 if (!m_SceneList.Contains(scene))
97 m_SceneList.Add(scene);
98 }
96 } 99 }
97 100
98 public void RemoveRegion(Scene scene) 101 public void RemoveRegion(Scene scene)
99 { 102 {
100 m_SceneList.Remove(scene); 103 lock (m_SceneList)
104 m_SceneList.Remove(scene);
101 } 105 }
102 106
103 public void RegionLoaded(Scene scene) 107 public void RegionLoaded(Scene scene)
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index c810242..9c6706f 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -36,6 +36,7 @@ using System.Xml;
36using log4net; 36using log4net;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
39using OpenSim.Framework.Serialization; 40using OpenSim.Framework.Serialization;
40using OpenSim.Framework.Serialization.External; 41using OpenSim.Framework.Serialization.External;
41using OpenSim.Region.CoreModules.World.Terrain; 42using OpenSim.Region.CoreModules.World.Terrain;
@@ -96,14 +97,42 @@ namespace OpenSim.Region.CoreModules.World.Archiver
96 97
97 /// <value> 98 /// <value>
98 /// Should the archive being loaded be merged with what is already on the region? 99 /// Should the archive being loaded be merged with what is already on the region?
100 /// Merging usually suppresses terrain and parcel loading
99 /// </value> 101 /// </value>
100 protected bool m_merge; 102 protected bool m_merge;
101 103
102 /// <value> 104 /// <value>
105 /// If true, force the loading of terrain from the oar file
106 /// </value>
107 protected bool m_forceTerrain;
108
109 /// <value>
110 /// If true, force the loading of parcels from the oar file
111 /// </value>
112 protected bool m_forceParcels;
113
114 /// <value>
103 /// Should we ignore any assets when reloading the archive? 115 /// Should we ignore any assets when reloading the archive?
104 /// </value> 116 /// </value>
105 protected bool m_skipAssets; 117 protected bool m_skipAssets;
106 118
119 /// <value>
120 /// Displacement added to each object as it is added to the world
121 /// </value>
122 protected Vector3 m_displacement = Vector3.Zero;
123
124 /// <value>
125 /// Rotation (in radians) to apply to the objects as they are loaded.
126 /// </value>
127 protected float m_rotation = 0f;
128
129 /// <value>
130 /// Center around which to apply the rotation relative to the origional oar position
131 /// </value>
132 protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f);
133
134 protected bool m_noObjects = false;
135
107 /// <summary> 136 /// <summary>
108 /// Used to cache lookups for valid uuids. 137 /// Used to cache lookups for valid uuids.
109 /// </summary> 138 /// </summary>
@@ -132,10 +161,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver
132 private IAssetService m_assetService = null; 161 private IAssetService m_assetService = null;
133 162
134 163
135 public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) 164 private UUID m_defaultUser;
165
166 public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary<string,object>options)
136 { 167 {
137 m_rootScene = scene; 168 m_rootScene = scene;
138 169
170 if (options.ContainsKey("default-user"))
171 {
172 m_defaultUser = (UUID)options["default-user"];
173 m_log.InfoFormat("Using User {0} as default user", m_defaultUser.ToString());
174 }
175 else
176 {
177 m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner;
178 }
179
139 m_loadPath = loadPath; 180 m_loadPath = loadPath;
140 try 181 try
141 { 182 {
@@ -150,26 +191,36 @@ namespace OpenSim.Region.CoreModules.World.Archiver
150 } 191 }
151 192
152 m_errorMessage = String.Empty; 193 m_errorMessage = String.Empty;
153 m_merge = merge; 194 m_merge = options.ContainsKey("merge");
154 m_skipAssets = skipAssets; 195 m_forceTerrain = options.ContainsKey("force-terrain");
196 m_forceParcels = options.ContainsKey("force-parcels");
197 m_noObjects = options.ContainsKey("no-objects");
198 m_skipAssets = options.ContainsKey("skipAssets");
155 m_requestId = requestId; 199 m_requestId = requestId;
200 m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero;
201 m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f;
202 m_rotationCenter = options.ContainsKey("rotation-center") ? (Vector3)options["rotation-center"]
203 : new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f);
156 204
157 // Zero can never be a valid user id 205 // Zero can never be a valid user or group id
158 m_validUserUuids[UUID.Zero] = false; 206 m_validUserUuids[UUID.Zero] = false;
207 m_validGroupUuids[UUID.Zero] = false;
159 208
160 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); 209 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
161 m_assetService = m_rootScene.AssetService; 210 m_assetService = m_rootScene.AssetService;
162 } 211 }
163 212
164 public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) 213 public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary<string, object>options)
165 { 214 {
166 m_rootScene = scene; 215 m_rootScene = scene;
167 m_loadPath = null; 216 m_loadPath = null;
168 m_loadStream = loadStream; 217 m_loadStream = loadStream;
169 m_merge = merge; 218 m_skipAssets = options.ContainsKey("skipAssets");
170 m_skipAssets = skipAssets; 219 m_merge = options.ContainsKey("merge");
171 m_requestId = requestId; 220 m_requestId = requestId;
172 221
222 m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner;
223
173 // Zero can never be a valid user id 224 // Zero can never be a valid user id
174 m_validUserUuids[UUID.Zero] = false; 225 m_validUserUuids[UUID.Zero] = false;
175 226
@@ -229,7 +280,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
229 280
230 // Process the file 281 // Process the file
231 282
232 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) 283 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH) && !m_noObjects)
233 { 284 {
234 sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); 285 sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
235 } 286 }
@@ -243,7 +294,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
243 if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) 294 if ((successfulAssetRestores + failedAssetRestores) % 250 == 0)
244 m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); 295 m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets...");
245 } 296 }
246 else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) 297 else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH) && (!m_merge || m_forceTerrain))
247 { 298 {
248 LoadTerrain(scene, filePath, data); 299 LoadTerrain(scene, filePath, data);
249 } 300 }
@@ -251,7 +302,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
251 { 302 {
252 LoadRegionSettings(scene, filePath, data, dearchivedScenes); 303 LoadRegionSettings(scene, filePath, data, dearchivedScenes);
253 } 304 }
254 else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) 305 else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels))
255 { 306 {
256 sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); 307 sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data));
257 } 308 }
@@ -321,7 +372,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
321 // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so 372 // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so
322 // that users can enter the scene. If we allow the scripts to start in the loop above 373 // that users can enter the scene. If we allow the scripts to start in the loop above
323 // then they significantly increase the time until the OAR finishes loading. 374 // then they significantly increase the time until the OAR finishes loading.
324 Util.FireAndForget(delegate(object o) 375 WorkManager.RunInThread(o =>
325 { 376 {
326 Thread.Sleep(15000); 377 Thread.Sleep(15000);
327 m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); 378 m_log.Info("[ARCHIVER]: Starting scripts in scene objects");
@@ -336,7 +387,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
336 387
337 sceneContext.SceneObjects.Clear(); 388 sceneContext.SceneObjects.Clear();
338 } 389 }
339 }); 390 }, null, string.Format("ReadArchiveStartScripts (request {0})", m_requestId));
340 391
341 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); 392 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive");
342 393
@@ -422,6 +473,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
422 // Reload serialized prims 473 // Reload serialized prims
423 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); 474 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
424 475
476 OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation);
477
425 UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; 478 UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject;
426 479
427 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); 480 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
@@ -445,6 +498,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver
445 498
446 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); 499 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
447 500
501 // Happily this does not do much to the object since it hasn't been added to the scene yet
502 if (!sceneObject.IsAttachment)
503 {
504 if (m_displacement != Vector3.Zero || m_rotation != 0f)
505 {
506 Vector3 pos = sceneObject.AbsolutePosition;
507 if (m_rotation != 0f)
508 {
509 // Rotate the object
510 sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation;
511 // Get object position relative to rotation axis
512 Vector3 offset = pos - m_rotationCenter;
513 // Rotate the object position
514 offset *= rot;
515 // Restore the object position back to relative to the region
516 pos = m_rotationCenter + offset;
517 }
518 if (m_displacement != Vector3.Zero)
519 {
520 pos += m_displacement;
521 }
522 sceneObject.AbsolutePosition = pos;
523 }
524 }
525
526
448 bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); 527 bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero);
449 528
450 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned 529 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
@@ -460,58 +539,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
460 oldTelehubUUID = UUID.Zero; 539 oldTelehubUUID = UUID.Zero;
461 } 540 }
462 541
463 // Try to retain the original creator/owner/lastowner if their uuid is present on this grid 542 ModifySceneObject(scene, sceneObject);
464 // or creator data is present. Otherwise, use the estate owner instead.
465 foreach (SceneObjectPart part in sceneObject.Parts)
466 {
467 if (part.CreatorData == null || part.CreatorData == string.Empty)
468 {
469 if (!ResolveUserUuid(scene, part.CreatorID))
470 part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
471 }
472 if (UserManager != null)
473 UserManager.AddUser(part.CreatorID, part.CreatorData);
474
475 if (!ResolveUserUuid(scene, part.OwnerID))
476 part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
477
478 if (!ResolveUserUuid(scene, part.LastOwnerID))
479 part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
480
481 if (!ResolveGroupUuid(part.GroupID))
482 part.GroupID = UUID.Zero;
483
484 // And zap any troublesome sit target information
485// part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
486// part.SitTargetPosition = new Vector3(0, 0, 0);
487
488 // Fix ownership/creator of inventory items
489 // Not doing so results in inventory items
490 // being no copy/no mod for everyone
491 lock (part.TaskInventory)
492 {
493 TaskInventoryDictionary inv = part.TaskInventory;
494 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
495 {
496 if (!ResolveUserUuid(scene, kvp.Value.OwnerID))
497 {
498 kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
499 }
500
501 if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty)
502 {
503 if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
504 kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
505 }
506
507 if (UserManager != null)
508 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
509
510 if (!ResolveGroupUuid(kvp.Value.GroupID))
511 kvp.Value.GroupID = UUID.Zero;
512 }
513 }
514 }
515 543
516 if (scene.AddRestoredSceneObject(sceneObject, true, false)) 544 if (scene.AddRestoredSceneObject(sceneObject, true, false))
517 { 545 {
@@ -535,6 +563,67 @@ namespace OpenSim.Region.CoreModules.World.Archiver
535 scene.RegionInfo.RegionSettings.ClearSpawnPoints(); 563 scene.RegionInfo.RegionSettings.ClearSpawnPoints();
536 } 564 }
537 } 565 }
566
567 /// <summary>
568 /// Optionally modify a loaded SceneObjectGroup. Currently this just ensures that the
569 /// User IDs and Group IDs are valid, but other manipulations could be done as well.
570 /// </summary>
571 private void ModifySceneObject(Scene scene, SceneObjectGroup sceneObject)
572 {
573 // Try to retain the original creator/owner/lastowner if their uuid is present on this grid
574 // or creator data is present. Otherwise, use the estate owner instead.
575 foreach (SceneObjectPart part in sceneObject.Parts)
576 {
577 if (string.IsNullOrEmpty(part.CreatorData))
578 {
579 if (!ResolveUserUuid(scene, part.CreatorID))
580 part.CreatorID = m_defaultUser;
581 }
582 if (UserManager != null)
583 UserManager.AddUser(part.CreatorID, part.CreatorData);
584
585 if (!(ResolveUserUuid(scene, part.OwnerID) || ResolveGroupUuid(part.OwnerID)))
586 part.OwnerID = m_defaultUser;
587
588 if (!(ResolveUserUuid(scene, part.LastOwnerID) || ResolveGroupUuid(part.LastOwnerID)))
589 part.LastOwnerID = m_defaultUser;
590
591 if (!ResolveGroupUuid(part.GroupID))
592 part.GroupID = UUID.Zero;
593
594 // And zap any troublesome sit target information
595 // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
596 // part.SitTargetPosition = new Vector3(0, 0, 0);
597
598 // Fix ownership/creator of inventory items
599 // Not doing so results in inventory items
600 // being no copy/no mod for everyone
601 lock (part.TaskInventory)
602 {
603 TaskInventoryDictionary inv = part.TaskInventory;
604 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
605 {
606 if (!(ResolveUserUuid(scene, kvp.Value.OwnerID) || ResolveGroupUuid(kvp.Value.OwnerID)))
607 {
608 kvp.Value.OwnerID = m_defaultUser;
609 }
610
611 if (string.IsNullOrEmpty(kvp.Value.CreatorData))
612 {
613 if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
614 kvp.Value.CreatorID = m_defaultUser;
615 }
616
617 if (UserManager != null)
618 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
619
620 if (!ResolveGroupUuid(kvp.Value.GroupID))
621 kvp.Value.GroupID = UUID.Zero;
622 }
623 }
624 }
625 }
626
538 627
539 /// <summary> 628 /// <summary>
540 /// Load serialized parcels. 629 /// Load serialized parcels.
@@ -549,15 +638,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver
549 foreach (string serialisedParcel in serialisedParcels) 638 foreach (string serialisedParcel in serialisedParcels)
550 { 639 {
551 LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); 640 LandData parcel = LandDataSerializer.Deserialize(serialisedParcel);
641
642 if (m_displacement != Vector3.Zero)
643 {
644 Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f);
645 parcel.AABBMin += parcelDisp;
646 parcel.AABBMax += parcelDisp;
647 }
552 648
553 // Validate User and Group UUID's 649 // Validate User and Group UUID's
554 650
651 if (!ResolveGroupUuid(parcel.GroupID))
652 parcel.GroupID = UUID.Zero;
653
555 if (parcel.IsGroupOwned) 654 if (parcel.IsGroupOwned)
556 { 655 {
557 if (!ResolveGroupUuid(parcel.GroupID)) 656 if (parcel.GroupID != UUID.Zero)
657 {
658 // In group-owned parcels, OwnerID=GroupID. This should already be the case, but let's make sure.
659 parcel.OwnerID = parcel.GroupID;
660 }
661 else
558 { 662 {
559 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; 663 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
560 parcel.GroupID = UUID.Zero;
561 parcel.IsGroupOwned = false; 664 parcel.IsGroupOwned = false;
562 } 665 }
563 } 666 }
@@ -565,9 +668,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
565 { 668 {
566 if (!ResolveUserUuid(scene, parcel.OwnerID)) 669 if (!ResolveUserUuid(scene, parcel.OwnerID))
567 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; 670 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
568
569 if (!ResolveGroupUuid(parcel.GroupID))
570 parcel.GroupID = UUID.Zero;
571 } 671 }
572 672
573 List<LandAccessEntry> accessList = new List<LandAccessEntry>(); 673 List<LandAccessEntry> accessList = new List<LandAccessEntry>();
@@ -604,13 +704,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
604 /// <returns></returns> 704 /// <returns></returns>
605 private bool ResolveUserUuid(Scene scene, UUID uuid) 705 private bool ResolveUserUuid(Scene scene, UUID uuid)
606 { 706 {
607 if (!m_validUserUuids.ContainsKey(uuid)) 707 lock (m_validUserUuids)
608 { 708 {
609 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); 709 if (!m_validUserUuids.ContainsKey(uuid))
610 m_validUserUuids.Add(uuid, account != null); 710 {
611 } 711 // Note: we call GetUserAccount() inside the lock because this UserID is likely
712 // to occur many times, and we only want to query the users service once.
713 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid);
714 m_validUserUuids.Add(uuid, account != null);
715 }
612 716
613 return m_validUserUuids[uuid]; 717 return m_validUserUuids[uuid];
718 }
614 } 719 }
615 720
616 /// <summary> 721 /// <summary>
@@ -620,22 +725,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver
620 /// <returns></returns> 725 /// <returns></returns>
621 private bool ResolveGroupUuid(UUID uuid) 726 private bool ResolveGroupUuid(UUID uuid)
622 { 727 {
623 if (uuid == UUID.Zero) 728 lock (m_validGroupUuids)
624 return true; // this means the object has no group
625
626 if (!m_validGroupUuids.ContainsKey(uuid))
627 { 729 {
628 bool exists; 730 if (!m_validGroupUuids.ContainsKey(uuid))
629 731 {
630 if (m_groupsModule == null) 732 bool exists;
631 exists = false; 733 if (m_groupsModule == null)
632 else 734 {
633 exists = (m_groupsModule.GetGroupRecord(uuid) != null); 735 exists = false;
736 }
737 else
738 {
739 // Note: we call GetGroupRecord() inside the lock because this GroupID is likely
740 // to occur many times, and we only want to query the groups service once.
741 exists = (m_groupsModule.GetGroupRecord(uuid) != null);
742 }
743 m_validGroupUuids.Add(uuid, exists);
744 }
634 745
635 m_validGroupUuids.Add(uuid, exists); 746 return m_validGroupUuids[uuid];
636 } 747 }
637
638 return m_validGroupUuids[uuid];
639 } 748 }
640 749
641 /// Load an asset 750 /// Load an asset
@@ -672,7 +781,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver
672 sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; 781 sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension];
673 782
674 if (assetType == (sbyte)AssetType.Unknown) 783 if (assetType == (sbyte)AssetType.Unknown)
784 {
675 m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); 785 m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid);
786 }
787 else if (assetType == (sbyte)AssetType.Object)
788 {
789 data = SceneObjectSerializer.ModifySerializedObject(UUID.Parse(uuid), data,
790 sog =>
791 {
792 ModifySceneObject(m_rootScene, sog);
793 return true;
794 });
795
796 if (data == null)
797 return false;
798 }
676 799
677 //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); 800 //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType);
678 801
@@ -796,9 +919,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
796 { 919 {
797 ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); 920 ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
798 921
799 MemoryStream ms = new MemoryStream(data); 922 using (MemoryStream ms = new MemoryStream(data))
800 terrainModule.LoadFromStream(terrainPath, ms); 923 {
801 ms.Close(); 924 if (m_displacement != Vector3.Zero || m_rotation != 0f)
925 {
926 Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y);
927 terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms);
928 }
929 else
930 {
931 terrainModule.LoadFromStream(terrainPath, ms);
932 }
933 }
802 934
803 m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); 935 m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath);
804 936
@@ -887,4 +1019,4 @@ namespace OpenSim.Region.CoreModules.World.Archiver
887 return dearchivedScenes; 1019 return dearchivedScenes;
888 } 1020 }
889 } 1021 }
890} \ No newline at end of file 1022}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
index 7bdd65c..cb2c7f1 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
@@ -36,6 +36,7 @@ using System.Xml;
36using log4net; 36using log4net;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
39using OpenSim.Framework.Serialization; 40using OpenSim.Framework.Serialization;
40using OpenSim.Region.CoreModules.World.Terrain; 41using OpenSim.Region.CoreModules.World.Terrain;
41using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
@@ -43,7 +44,9 @@ using OpenSim.Region.Framework.Scenes;
43using Ionic.Zlib; 44using Ionic.Zlib;
44using GZipStream = Ionic.Zlib.GZipStream; 45using GZipStream = Ionic.Zlib.GZipStream;
45using CompressionMode = Ionic.Zlib.CompressionMode; 46using CompressionMode = Ionic.Zlib.CompressionMode;
47using CompressionLevel = Ionic.Zlib.CompressionLevel;
46using OpenSim.Framework.Serialization.External; 48using OpenSim.Framework.Serialization.External;
49using PermissionMask = OpenSim.Framework.PermissionMask;
47 50
48namespace OpenSim.Region.CoreModules.World.Archiver 51namespace OpenSim.Region.CoreModules.World.Archiver
49{ 52{
@@ -78,7 +81,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
78 /// Determines which objects will be included in the archive, according to their permissions. 81 /// Determines which objects will be included in the archive, according to their permissions.
79 /// Default is null, meaning no permission checks. 82 /// Default is null, meaning no permission checks.
80 /// </summary> 83 /// </summary>
81 public string CheckPermissions { get; set; } 84 public string FilterContent { get; set; }
82 85
83 protected Scene m_rootScene; 86 protected Scene m_rootScene;
84 protected Stream m_saveStream; 87 protected Stream m_saveStream;
@@ -129,7 +132,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
129 132
130 MultiRegionFormat = false; 133 MultiRegionFormat = false;
131 SaveAssets = true; 134 SaveAssets = true;
132 CheckPermissions = null; 135 FilterContent = null;
133 } 136 }
134 137
135 /// <summary> 138 /// <summary>
@@ -148,7 +151,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
148 151
149 Object temp; 152 Object temp;
150 if (options.TryGetValue("checkPermissions", out temp)) 153 if (options.TryGetValue("checkPermissions", out temp))
151 CheckPermissions = (string)temp; 154 FilterContent = (string)temp;
152 155
153 156
154 // Find the regions to archive 157 // Find the regions to archive
@@ -177,7 +180,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
177 180
178 // Archive the regions 181 // Archive the regions
179 182
180 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>(); 183 Dictionary<UUID, sbyte> assetUuids = new Dictionary<UUID, sbyte>();
181 184
182 scenesGroup.ForEachScene(delegate(Scene scene) 185 scenesGroup.ForEachScene(delegate(Scene scene)
183 { 186 {
@@ -198,7 +201,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
198 m_rootScene.AssetService, m_rootScene.UserAccountService, 201 m_rootScene.AssetService, m_rootScene.UserAccountService,
199 m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); 202 m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets);
200 203
201 Util.FireAndForget(o => ar.Execute()); 204 WorkManager.RunInThread(o => ar.Execute(), null, "Archive Assets Request");
202 205
203 // CloseArchive() will be called from ReceivedAllAssets() 206 // CloseArchive() will be called from ReceivedAllAssets()
204 } 207 }
@@ -215,9 +218,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
215 } 218 }
216 } 219 }
217 220
218 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) 221 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, sbyte> assetUuids)
219 { 222 {
220 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); 223 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.Name);
221 224
222 EntityBase[] entities = scene.GetEntities(); 225 EntityBase[] entities = scene.GetEntities();
223 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); 226 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
@@ -236,7 +239,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
236 239
237 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) 240 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
238 { 241 {
239 if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule)) 242 if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, FilterContent, permissionsModule))
240 { 243 {
241 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR. 244 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
242 ++numObjectsSkippedPermissions; 245 ++numObjectsSkippedPermissions;
@@ -251,13 +254,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver
251 254
252 if (SaveAssets) 255 if (SaveAssets)
253 { 256 {
254 UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService); 257 UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService, assetUuids);
255 int prevAssets = assetUuids.Count; 258 int prevAssets = assetUuids.Count;
256 259
257 foreach (SceneObjectGroup sceneObject in sceneObjects) 260 foreach (SceneObjectGroup sceneObject in sceneObjects)
258 { 261 assetGatherer.AddForInspection(sceneObject);
259 assetGatherer.GatherAssetUuids(sceneObject, assetUuids); 262
260 } 263 assetGatherer.GatherAll();
261 264
262 m_log.DebugFormat( 265 m_log.DebugFormat(
263 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", 266 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
@@ -275,16 +278,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
275 RegionSettings regionSettings = scene.RegionInfo.RegionSettings; 278 RegionSettings regionSettings = scene.RegionInfo.RegionSettings;
276 279
277 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) 280 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
278 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture; 281 assetUuids[regionSettings.TerrainTexture1] = (sbyte)AssetType.Texture;
279 282
280 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) 283 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
281 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture; 284 assetUuids[regionSettings.TerrainTexture2] = (sbyte)AssetType.Texture;
282 285
283 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) 286 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
284 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture; 287 assetUuids[regionSettings.TerrainTexture3] = (sbyte)AssetType.Texture;
285 288
286 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) 289 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
287 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture; 290 assetUuids[regionSettings.TerrainTexture4] = (sbyte)AssetType.Texture;
288 291
289 Save(scene, sceneObjects, regionDir); 292 Save(scene, sceneObjects, regionDir);
290 } 293 }
@@ -294,12 +297,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver
294 /// </summary> 297 /// </summary>
295 /// <param name="user">The user</param> 298 /// <param name="user">The user</param>
296 /// <param name="objGroup">The object group</param> 299 /// <param name="objGroup">The object group</param>
297 /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param> 300 /// <param name="filterContent">Which permissions to check: "C" = Copy, "T" = Transfer</param>
298 /// <param name="permissionsModule">The scene's permissions module</param> 301 /// <param name="permissionsModule">The scene's permissions module</param>
299 /// <returns>Whether the user is allowed to export the object to an OAR</returns> 302 /// <returns>Whether the user is allowed to export the object to an OAR</returns>
300 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule) 303 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string filterContent, IPermissionsModule permissionsModule)
301 { 304 {
302 if (checkPermissions == null) 305 if (filterContent == null)
303 return true; 306 return true;
304 307
305 if (permissionsModule == null) 308 if (permissionsModule == null)
@@ -341,9 +344,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
341 canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0; 344 canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
342 345
343 bool partPermitted = true; 346 bool partPermitted = true;
344 if (checkPermissions.Contains("C") && !canCopy) 347 if (filterContent.Contains("C") && !canCopy)
345 partPermitted = false; 348 partPermitted = false;
346 if (checkPermissions.Contains("T") && !canTransfer) 349 if (filterContent.Contains("T") && !canTransfer)
347 partPermitted = false; 350 partPermitted = false;
348 351
349 // If the user is the Creator of the object then it can always be included in the OAR 352 // If the user is the Creator of the object then it can always be included in the OAR
@@ -532,7 +535,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
532 if (isMegaregion) 535 if (isMegaregion)
533 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); 536 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
534 else 537 else
535 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); 538 size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY);
536 539
537 xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); 540 xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
538 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); 541 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
@@ -568,10 +571,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
568 string terrainPath = String.Format("{0}{1}{2}.r32", 571 string terrainPath = String.Format("{0}{1}{2}.r32",
569 regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName); 572 regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName);
570 573
571 MemoryStream ms = new MemoryStream(); 574 using (MemoryStream ms = new MemoryStream())
572 scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms); 575 {
573 m_archiveWriter.WriteFile(terrainPath, ms.ToArray()); 576 scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms);
574 ms.Close(); 577 m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
578 }
575 579
576 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive."); 580 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
577 581
@@ -587,19 +591,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver
587 } 591 }
588 } 592 }
589 593
590 protected void ReceivedAllAssets( 594 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
591 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
592 { 595 {
593 foreach (UUID uuid in assetsNotFoundUuids) 596 string errorMessage;
597
598 if (timedOut)
594 { 599 {
595 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); 600 errorMessage = "Loading assets timed out";
596 } 601 }
602 else
603 {
604 foreach (UUID uuid in assetsNotFoundUuids)
605 {
606 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
607 }
597 608
598 // m_log.InfoFormat( 609 // m_log.InfoFormat(
599 // "[ARCHIVER]: Received {0} of {1} assets requested", 610 // "[ARCHIVER]: Received {0} of {1} assets requested",
600 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); 611 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
601 612
602 CloseArchive(String.Empty); 613 errorMessage = String.Empty;
614 }
615
616 CloseArchive(errorMessage);
603 } 617 }
604 618
605 /// <summary> 619 /// <summary>
@@ -626,4 +640,4 @@ namespace OpenSim.Region.CoreModules.World.Archiver
626 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); 640 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
627 } 641 }
628 } 642 }
629} \ No newline at end of file 643}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
index 1be6386..6a09caf 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
@@ -33,11 +33,14 @@ using log4net;
33using NDesk.Options; 33using NDesk.Options;
34using Nini.Config; 34using Nini.Config;
35using Mono.Addins; 35using Mono.Addins;
36
36using OpenSim.Framework; 37using OpenSim.Framework;
37using OpenSim.Framework.Console; 38using OpenSim.Framework.Console;
38using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40 41
42using OpenMetaverse;
43
41namespace OpenSim.Region.CoreModules.World.Archiver 44namespace OpenSim.Region.CoreModules.World.Archiver
42{ 45{
43 /// <summary> 46 /// <summary>
@@ -101,9 +104,62 @@ namespace OpenSim.Region.CoreModules.World.Archiver
101 { 104 {
102 bool mergeOar = false; 105 bool mergeOar = false;
103 bool skipAssets = false; 106 bool skipAssets = false;
107 bool forceTerrain = false;
108 bool forceParcels = false;
109 bool noObjects = false;
110 Vector3 displacement = new Vector3(0f, 0f, 0f);
111 String defaultUser = "";
112 float rotation = 0f;
113 Vector3 rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0);
104 114
105 OptionSet options = new OptionSet().Add("m|merge", delegate (string v) { mergeOar = v != null; }); 115 OptionSet options = new OptionSet();
106 options.Add("s|skip-assets", delegate (string v) { skipAssets = v != null; }); 116 options.Add("m|merge", delegate (string v) { mergeOar = (v != null); });
117 options.Add("s|skip-assets", delegate (string v) { skipAssets = (v != null); });
118 options.Add("force-terrain", delegate (string v) { forceTerrain = (v != null); });
119 options.Add("forceterrain", delegate (string v) { forceTerrain = (v != null); }); // downward compatibility
120 options.Add("force-parcels", delegate (string v) { forceParcels = (v != null); });
121 options.Add("forceparcels", delegate (string v) { forceParcels = (v != null); }); // downward compatibility
122 options.Add("no-objects", delegate (string v) { noObjects = (v != null); });
123 options.Add("default-user=", delegate(string v) { defaultUser = (v == null) ? "" : v; });
124 options.Add("displacement=", delegate (string v) {
125 try
126 {
127 displacement = v == null ? Vector3.Zero : Vector3.Parse(v);
128 }
129 catch
130 {
131 m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement");
132 m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --displacement \"<128,128,0>\"");
133 return;
134 }
135 });
136 options.Add("rotation=", delegate(string v)
137 {
138 try
139 {
140 rotation = v == null ? 0f : float.Parse(v);
141 }
142 catch
143 {
144 m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation");
145 m_log.ErrorFormat("[ARCHIVER MODULE] Must be an angle in degrees between -360 and +360: --rotation 45");
146 return;
147 }
148 // Convert to radians for internals
149 rotation = Util.Clamp<float>(rotation, -359f, 359f) / 180f * (float)Math.PI;
150 });
151 options.Add("rotation-center=", delegate (string v) {
152 try
153 {
154 rotationCenter = v == null ? Vector3.Zero : Vector3.Parse(v);
155 }
156 catch
157 {
158 m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation displacement");
159 m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --rotation-center \"<128,128,0>\"");
160 return;
161 }
162 });
107 163
108 // Send a message to the region ready module 164 // Send a message to the region ready module
109 /* bluewall* Disable this for the time being 165 /* bluewall* Disable this for the time being
@@ -122,13 +178,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver
122// foreach (string param in mainParams) 178// foreach (string param in mainParams)
123// m_log.DebugFormat("GOT PARAM [{0}]", param); 179// m_log.DebugFormat("GOT PARAM [{0}]", param);
124 180
181 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
182 if (mergeOar) archiveOptions.Add("merge", null);
183 if (skipAssets) archiveOptions.Add("skipAssets", null);
184 if (forceTerrain) archiveOptions.Add("force-terrain", null);
185 if (forceParcels) archiveOptions.Add("force-parcels", null);
186 if (noObjects) archiveOptions.Add("no-objects", null);
187 if (defaultUser != "")
188 {
189 UUID defaultUserUUID = UUID.Zero;
190 try
191 {
192 defaultUserUUID = Scene.UserManagementModule.GetUserIdByName(defaultUser);
193 }
194 catch
195 {
196 m_log.ErrorFormat("[ARCHIVER MODULE] default user must be in format \"First Last\"", defaultUser);
197 }
198 if (defaultUserUUID == UUID.Zero)
199 {
200 m_log.ErrorFormat("[ARCHIVER MODULE] cannot find specified default user {0}", defaultUser);
201 return;
202 }
203 else
204 {
205 archiveOptions.Add("default-user", defaultUserUUID);
206 }
207 }
208 archiveOptions.Add("displacement", displacement);
209 archiveOptions.Add("rotation", rotation);
210 archiveOptions.Add("rotation-center", rotationCenter);
211
125 if (mainParams.Count > 2) 212 if (mainParams.Count > 2)
126 { 213 {
127 DearchiveRegion(mainParams[2], mergeOar, skipAssets, Guid.Empty); 214 DearchiveRegion(mainParams[2], Guid.Empty, archiveOptions);
128 } 215 }
129 else 216 else
130 { 217 {
131 DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, mergeOar, skipAssets, Guid.Empty); 218 DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, Guid.Empty, archiveOptions);
132 } 219 }
133 } 220 }
134 221
@@ -198,25 +285,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver
198 285
199 public void DearchiveRegion(string loadPath) 286 public void DearchiveRegion(string loadPath)
200 { 287 {
201 DearchiveRegion(loadPath, false, false, Guid.Empty); 288 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
289 DearchiveRegion(loadPath, Guid.Empty, archiveOptions);
202 } 290 }
203 291
204 public void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId) 292 public void DearchiveRegion(string loadPath, Guid requestId, Dictionary<string,object> options)
205 { 293 {
206 m_log.InfoFormat( 294 m_log.InfoFormat(
207 "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); 295 "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath);
208 296
209 new ArchiveReadRequest(Scene, loadPath, merge, skipAssets, requestId).DearchiveRegion(); 297 new ArchiveReadRequest(Scene, loadPath, requestId, options).DearchiveRegion();
210 } 298 }
211 299
212 public void DearchiveRegion(Stream loadStream) 300 public void DearchiveRegion(Stream loadStream)
213 { 301 {
214 DearchiveRegion(loadStream, false, false, Guid.Empty); 302 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
303 DearchiveRegion(loadStream, Guid.Empty, archiveOptions);
215 } 304 }
216 305
217 public void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId) 306 public void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary<string, object> options)
218 { 307 {
219 new ArchiveReadRequest(Scene, loadStream, merge, skipAssets, requestId).DearchiveRegion(); 308 new ArchiveReadRequest(Scene, loadStream, requestId, options).DearchiveRegion();
220 } 309 }
221 } 310 }
222} 311}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
index 95d109c..a8eae56 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
@@ -145,17 +145,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
145 m_assetsWritten++; 145 m_assetsWritten++;
146 146
147 //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten); 147 //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten);
148 148
149 if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0) 149 if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0)
150 m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); 150 m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten);
151 } 151 }
152 152
153 /// <summary>
154 /// Only call this if you need to force a close on the underlying writer.
155 /// </summary>
156 public void ForceClose()
157 {
158 m_archiveWriter.Close();
159 }
160 } 153 }
161} 154}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index 103eb47..db66c83 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -33,6 +33,7 @@ using System.Timers;
33using log4net; 33using log4net;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
37using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
38using OpenSim.Services.Interfaces; 39using OpenSim.Services.Interfaces;
@@ -50,7 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
50 /// Method called when all the necessary assets for an archive request have been received. 51 /// Method called when all the necessary assets for an archive request have been received.
51 /// </summary> 52 /// </summary>
52 public delegate void AssetsRequestCallback( 53 public delegate void AssetsRequestCallback(
53 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids); 54 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut);
54 55
55 enum RequestState 56 enum RequestState
56 { 57 {
@@ -81,7 +82,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
81 /// <value> 82 /// <value>
82 /// uuids to request 83 /// uuids to request
83 /// </value> 84 /// </value>
84 protected IDictionary<UUID, AssetType> m_uuids; 85 protected IDictionary<UUID, sbyte> m_uuids;
85 86
86 /// <value> 87 /// <value>
87 /// Callback used when all the assets requested have been received. 88 /// Callback used when all the assets requested have been received.
@@ -115,7 +116,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
115 protected Dictionary<string, object> m_options; 116 protected Dictionary<string, object> m_options;
116 117
117 protected internal AssetsRequest( 118 protected internal AssetsRequest(
118 AssetsArchiver assetsArchiver, IDictionary<UUID, AssetType> uuids, 119 AssetsArchiver assetsArchiver, IDictionary<UUID, sbyte> uuids,
119 IAssetService assetService, IUserAccountService userService, 120 IAssetService assetService, IUserAccountService userService,
120 UUID scope, Dictionary<string, object> options, 121 UUID scope, Dictionary<string, object> options,
121 AssetsRequestCallback assetsRequestCallback) 122 AssetsRequestCallback assetsRequestCallback)
@@ -143,19 +144,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver
143 m_requestState = RequestState.Running; 144 m_requestState = RequestState.Running;
144 145
145 m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired); 146 m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired);
146 147
147 // We can stop here if there are no assets to fetch 148 // We can stop here if there are no assets to fetch
148 if (m_repliesRequired == 0) 149 if (m_repliesRequired == 0)
149 { 150 {
150 m_requestState = RequestState.Completed; 151 m_requestState = RequestState.Completed;
151 PerformAssetsRequestCallback(null); 152 PerformAssetsRequestCallback(false);
152 return; 153 return;
153 } 154 }
154 155
155 m_requestCallbackTimer.Enabled = true; 156 m_requestCallbackTimer.Enabled = true;
156 157
157 foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids) 158 foreach (KeyValuePair<UUID, sbyte> kvp in m_uuids)
158 { 159 {
160// m_log.DebugFormat("[ARCHIVER]: Requesting asset {0}", kvp.Key);
161
159// m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); 162// m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback);
160 AssetBase asset = m_assetService.Get(kvp.Key.ToString()); 163 AssetBase asset = m_assetService.Get(kvp.Key.ToString());
161 PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); 164 PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset);
@@ -164,7 +167,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
164 167
165 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) 168 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args)
166 { 169 {
167 bool close = true; 170 bool timedOut = true;
168 171
169 try 172 try
170 { 173 {
@@ -174,7 +177,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
174 // the final request came in (assuming that such a thing is possible) 177 // the final request came in (assuming that such a thing is possible)
175 if (m_requestState == RequestState.Completed) 178 if (m_requestState == RequestState.Completed)
176 { 179 {
177 close = false; 180 timedOut = false;
178 return; 181 return;
179 } 182 }
180 183
@@ -223,8 +226,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
223 } 226 }
224 finally 227 finally
225 { 228 {
226 if (close) 229 if (timedOut)
227 m_assetsArchiver.ForceClose(); 230 WorkManager.RunInThread(PerformAssetsRequestCallback, true, "Archive Assets Request Callback");
228 } 231 }
229 } 232 }
230 233
@@ -233,9 +236,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
233 // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer 236 // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer
234 if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown) 237 if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown)
235 { 238 {
236 AssetType type = (AssetType)assetType; 239 m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, SLUtil.AssetTypeFromCode((sbyte)assetType));
237 m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, type); 240 fetchedAsset.Type = (sbyte)assetType;
238 fetchedAsset.Type = (sbyte)type;
239 } 241 }
240 242
241 AssetRequestCallback(fetchedAssetID, this, fetchedAsset); 243 AssetRequestCallback(fetchedAssetID, this, fetchedAsset);
@@ -294,7 +296,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
294 296
295 // We want to stop using the asset cache thread asap 297 // We want to stop using the asset cache thread asap
296 // as we now need to do the work of producing the rest of the archive 298 // as we now need to do the work of producing the rest of the archive
297 Util.FireAndForget(PerformAssetsRequestCallback); 299 WorkManager.RunInThread(PerformAssetsRequestCallback, false, "Archive Assets Request Callback");
298 } 300 }
299 else 301 else
300 { 302 {
@@ -315,9 +317,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
315 { 317 {
316 Culture.SetCurrentCulture(); 318 Culture.SetCurrentCulture();
317 319
320 Boolean timedOut = (Boolean)o;
321
318 try 322 try
319 { 323 {
320 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids); 324 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids, timedOut);
321 } 325 }
322 catch (Exception e) 326 catch (Exception e)
323 { 327 {
@@ -331,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
331 if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) 335 if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home"))
332 { 336 {
333 //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); 337 //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID);
334 string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), m_options["home"].ToString(), m_userAccountService, m_scopeID); 338 string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), string.Empty, m_options["home"].ToString(), m_userAccountService, m_scopeID);
335 asset.Data = Utils.StringToBytes(xml); 339 asset.Data = Utils.StringToBytes(xml);
336 } 340 }
337 return asset; 341 return asset;
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
index eec1cec..9f197f5 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -45,7 +45,6 @@ using OpenSim.Region.Framework.Scenes;
45using OpenSim.Region.Framework.Scenes.Serialization; 45using OpenSim.Region.Framework.Scenes.Serialization;
46using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; 46using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
47using OpenSim.Tests.Common; 47using OpenSim.Tests.Common;
48using OpenSim.Tests.Common.Mock;
49using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; 48using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
50using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; 49using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader;
51using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; 50using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter;
@@ -224,8 +223,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
224 223
225 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 224 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
226 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 225 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
227 226
228 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 227 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
228 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
229 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); 229 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
230 230
231 Assert.That(arr.ControlFileLoaded, Is.True); 231 Assert.That(arr.ControlFileLoaded, Is.True);
@@ -308,8 +308,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
308 308
309 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 309 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
310 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 310 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
311 311
312 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 312 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
313 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
313 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); 314 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
314 315
315 Assert.That(arr.ControlFileLoaded, Is.True); 316 Assert.That(arr.ControlFileLoaded, Is.True);
@@ -577,13 +578,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
577 ArchiveConstants.CONTROL_FILE_PATH, 578 ArchiveConstants.CONTROL_FILE_PATH,
578 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); 579 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
579 580
580 LandObject lo = new LandObject(groupID, true, null); 581 LandObject lo = new LandObject(groupID, true, m_scene);
581 lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); 582 lo.SetLandBitmap(lo.BasicFullRegionLandBitmap());
582 LandData ld = lo.LandData; 583 LandData ld = lo.LandData;
583 ld.GlobalID = landID; 584 ld.GlobalID = landID;
584 585
585 string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); 586 string ldPath = ArchiveConstants.CreateOarLandDataPath(ld);
586 tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null)); 587 Dictionary<string, object> options = new Dictionary<string, object>();
588 tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, options));
587 tar.Close(); 589 tar.Close();
588 590
589 oarStream = new MemoryStream(oarStream.ToArray()); 591 oarStream = new MemoryStream(oarStream.ToArray());
@@ -752,7 +754,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
752 byte[] archive = archiveWriteStream.ToArray(); 754 byte[] archive = archiveWriteStream.ToArray();
753 MemoryStream archiveReadStream = new MemoryStream(archive); 755 MemoryStream archiveReadStream = new MemoryStream(archive);
754 756
755 m_archiverModule.DearchiveRegion(archiveReadStream, true, false, Guid.Empty); 757 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
758 archiveOptions.Add("merge", null);
759 m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions);
756 760
757 SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); 761 SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name);
758 Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); 762 Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge");
@@ -860,7 +864,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
860 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 864 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
861 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 865 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
862 866
863 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 867 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
868 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
864 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); 869 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
865 870
866 Assert.That(arr.ControlFileLoaded, Is.True); 871 Assert.That(arr.ControlFileLoaded, Is.True);
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
index 4d49794..702b503 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
@@ -39,6 +39,7 @@ using OpenSim.Framework.Console;
39using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 39using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Services.Interfaces;
42 43
43namespace OpenSim.Region.CoreModules.World.Estate 44namespace OpenSim.Region.CoreModules.World.Estate
44{ 45{
@@ -50,9 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 52
52 protected EstateManagementModule m_module; 53 protected EstateManagementModule m_module;
53 54
54 protected Commander m_commander = new Commander("estate");
55
56 public EstateManagementCommands(EstateManagementModule module) 55 public EstateManagementCommands(EstateManagementModule module)
57 { 56 {
58 m_module = module; 57 m_module = module;
@@ -60,7 +59,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
60 59
61 public void Initialise() 60 public void Initialise()
62 { 61 {
63 m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); 62// m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName);
64 63
65 m_module.Scene.AddCommand("Regions", m_module, "set terrain texture", 64 m_module.Scene.AddCommand("Regions", m_module, "set terrain texture",
66 "set terrain texture <number> <uuid> [<x>] [<y>]", 65 "set terrain texture <number> <uuid> [<x>] [<y>]",
@@ -76,12 +75,19 @@ namespace OpenSim.Region.CoreModules.World.Estate
76 " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", 75 " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.",
77 consoleSetTerrainHeights); 76 consoleSetTerrainHeights);
78 77
78 m_module.Scene.AddCommand("Regions", m_module, "set water height",
79 "set water height <height> [<x>] [<y>]",
80 "Sets the water height in meters. If <x> and <y> are specified, it will only set it on regions with a matching coordinate. " +
81 "Specify -1 in <x> or <y> to wildcard that coordinate.",
82 consoleSetWaterHeight);
83
79 m_module.Scene.AddCommand( 84 m_module.Scene.AddCommand(
80 "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); 85 "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand);
81 } 86 }
82 87
83 public void Close() {} 88 public void Close() {}
84 89
90 #region CommandHandlers
85 protected void consoleSetTerrainTexture(string module, string[] args) 91 protected void consoleSetTerrainTexture(string module, string[] args)
86 { 92 {
87 string num = args[3]; 93 string num = args[3];
@@ -121,7 +127,29 @@ namespace OpenSim.Region.CoreModules.World.Estate
121 } 127 }
122 } 128 }
123 } 129 }
124 130 protected void consoleSetWaterHeight(string module, string[] args)
131 {
132 string heightstring = args[3];
133
134 int x = (args.Length > 4 ? int.Parse(args[4]) : -1);
135 int y = (args.Length > 5 ? int.Parse(args[5]) : -1);
136
137 if (x == -1 || m_module.Scene.RegionInfo.RegionLocX == x)
138 {
139 if (y == -1 || m_module.Scene.RegionInfo.RegionLocY == y)
140 {
141 double selectedheight = double.Parse(heightstring);
142
143 m_log.Debug("[ESTATEMODULE]: Setting water height in " + m_module.Scene.RegionInfo.RegionName + " to " +
144 string.Format(" {0}", selectedheight));
145 m_module.Scene.RegionInfo.RegionSettings.WaterHeight = selectedheight;
146
147 m_module.Scene.RegionInfo.RegionSettings.Save();
148 m_module.TriggerRegionInfoChange();
149 m_module.sendRegionHandshakeToAll();
150 }
151 }
152 }
125 protected void consoleSetTerrainHeights(string module, string[] args) 153 protected void consoleSetTerrainHeights(string module, string[] args)
126 { 154 {
127 string num = args[3]; 155 string num = args[3];
@@ -196,6 +224,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
196 es.EstateName, es.EstateID, m_module.UserManager.GetUserName(es.EstateOwner)); 224 es.EstateName, es.EstateID, m_module.UserManager.GetUserName(es.EstateOwner));
197 225
198 MainConsole.Instance.Output(report.ToString()); 226 MainConsole.Instance.Output(report.ToString());
199 } 227 }
228 #endregion
200 } 229 }
201} \ No newline at end of file 230} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index 311707b..80fa08a 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -32,6 +32,7 @@ using System.IO;
32using System.Linq; 32using System.Linq;
33using System.Reflection; 33using System.Reflection;
34using System.Security; 34using System.Security;
35using System.Timers;
35using log4net; 36using log4net;
36using Mono.Addins; 37using Mono.Addins;
37using Nini.Config; 38using Nini.Config;
@@ -39,6 +40,7 @@ using OpenMetaverse;
39using OpenSim.Framework; 40using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
42using RegionFlags = OpenMetaverse.RegionFlags; 44using RegionFlags = OpenMetaverse.RegionFlags;
43 45
44namespace OpenSim.Region.CoreModules.World.Estate 46namespace OpenSim.Region.CoreModules.World.Estate
@@ -48,6 +50,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
48 { 50 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 52
53 private Timer m_regionChangeTimer = new Timer();
51 public Scene Scene { get; private set; } 54 public Scene Scene { get; private set; }
52 public IUserManagement UserManager { get; private set; } 55 public IUserManagement UserManager { get; private set; }
53 56
@@ -112,13 +115,287 @@ namespace OpenSim.Region.CoreModules.World.Estate
112 115
113 #endregion 116 #endregion
114 117
118 #region IEstateModule Functions
119 public uint GetRegionFlags()
120 {
121 RegionFlags flags = RegionFlags.None;
122
123 // Fully implemented
124 //
125 if (Scene.RegionInfo.RegionSettings.AllowDamage)
126 flags |= RegionFlags.AllowDamage;
127 if (Scene.RegionInfo.RegionSettings.BlockTerraform)
128 flags |= RegionFlags.BlockTerraform;
129 if (!Scene.RegionInfo.RegionSettings.AllowLandResell)
130 flags |= RegionFlags.BlockLandResell;
131 if (Scene.RegionInfo.RegionSettings.DisableCollisions)
132 flags |= RegionFlags.SkipCollisions;
133 if (Scene.RegionInfo.RegionSettings.DisableScripts)
134 flags |= RegionFlags.SkipScripts;
135 if (Scene.RegionInfo.RegionSettings.DisablePhysics)
136 flags |= RegionFlags.SkipPhysics;
137 if (Scene.RegionInfo.RegionSettings.BlockFly)
138 flags |= RegionFlags.NoFly;
139 if (Scene.RegionInfo.RegionSettings.RestrictPushing)
140 flags |= RegionFlags.RestrictPushObject;
141 if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide)
142 flags |= RegionFlags.AllowParcelChanges;
143 if (Scene.RegionInfo.RegionSettings.BlockShowInSearch)
144 flags |= RegionFlags.BlockParcelSearch;
145
146 if (Scene.RegionInfo.RegionSettings.FixedSun)
147 flags |= RegionFlags.SunFixed;
148 if (Scene.RegionInfo.RegionSettings.Sandbox)
149 flags |= RegionFlags.Sandbox;
150 if (Scene.RegionInfo.EstateSettings.AllowVoice)
151 flags |= RegionFlags.AllowVoice;
152 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
153 flags |= RegionFlags.AllowLandmark;
154 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
155 flags |= RegionFlags.AllowSetHome;
156 if (Scene.RegionInfo.EstateSettings.BlockDwell)
157 flags |= RegionFlags.BlockDwell;
158 if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport)
159 flags |= RegionFlags.ResetHomeOnTeleport;
160
161
162 // TODO: SkipUpdateInterestList
163
164 // Omitted
165 //
166 // Omitted: NullLayer (what is that?)
167 // Omitted: SkipAgentAction (what does it do?)
168
169 return (uint)flags;
170 }
171
172 public bool IsManager(UUID avatarID)
173 {
174 if (avatarID == Scene.RegionInfo.EstateSettings.EstateOwner)
175 return true;
176
177 List<UUID> ems = new List<UUID>(Scene.RegionInfo.EstateSettings.EstateManagers);
178 if (ems.Contains(avatarID))
179 return true;
180
181 return false;
182 }
183
184 public void sendRegionHandshakeToAll()
185 {
186 Scene.ForEachClient(sendRegionHandshake);
187 }
188
189 public void TriggerEstateInfoChange()
190 {
191 ChangeDelegate change = OnEstateInfoChange;
192
193 if (change != null)
194 change(Scene.RegionInfo.RegionID);
195 }
196
197 public void TriggerRegionInfoChange()
198 {
199 m_regionChangeTimer.Stop();
200 m_regionChangeTimer.Start();
201
202 ChangeDelegate change = OnRegionInfoChange;
203
204 if (change != null)
205 change(Scene.RegionInfo.RegionID);
206 }
207
208 public void setEstateTerrainBaseTexture(int level, UUID texture)
209 {
210 setEstateTerrainBaseTexture(null, level, texture);
211 sendRegionHandshakeToAll();
212 }
213
214 public void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue)
215 {
216 setEstateTerrainTextureHeights(null, corner, lowValue, highValue);
217 }
218
219 public bool IsTerrainXfer(ulong xferID)
220 {
221 lock (this)
222 {
223 if (TerrainUploader == null)
224 return false;
225 else
226 return TerrainUploader.XferID == xferID;
227 }
228 }
229
230 public string SetEstateOwner(int estateID, UserAccount account)
231 {
232 string response;
233
234 // get the current settings from DB
235 EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
236 if (dbSettings.EstateID == 0)
237 {
238 response = String.Format("No estate found with ID {0}", estateID);
239 }
240 else if (account.PrincipalID == dbSettings.EstateOwner)
241 {
242 response = String.Format("Estate already belongs to {0} ({1} {2})", account.PrincipalID, account.FirstName, account.LastName);
243 }
244 else
245 {
246 dbSettings.EstateOwner = account.PrincipalID;
247 Scene.EstateDataService.StoreEstateSettings(dbSettings);
248 response = String.Empty;
249
250 // make sure there's a log entry to document the change
251 m_log.InfoFormat("[ESTATE]: Estate Owner for {0} changed to {1} ({2} {3})", dbSettings.EstateName,
252 account.PrincipalID, account.FirstName, account.LastName);
253
254 // propagate the change
255 List<UUID> regions = Scene.GetEstateRegions(estateID);
256 UUID regionId = (regions.Count() > 0) ? regions.ElementAt(0) : UUID.Zero;
257 if (regionId != UUID.Zero)
258 {
259 ChangeDelegate change = OnEstateInfoChange;
260
261 if (change != null)
262 change(regionId);
263 }
264
265 }
266 return response;
267 }
268
269 public string SetEstateName(int estateID, string newName)
270 {
271 string response;
272
273 // get the current settings from DB
274 EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
275
276 if (dbSettings.EstateID == 0)
277 {
278 response = String.Format("No estate found with ID {0}", estateID);
279 }
280 else if (newName == dbSettings.EstateName)
281 {
282 response = String.Format("Estate {0} is already named \"{1}\"", estateID, newName);
283 }
284 else
285 {
286 List<int> estates = Scene.EstateDataService.GetEstates(newName);
287 if (estates.Count() > 0)
288 {
289 response = String.Format("An estate named \"{0}\" already exists.", newName);
290 }
291 else
292 {
293 string oldName = dbSettings.EstateName;
294 dbSettings.EstateName = newName;
295 Scene.EstateDataService.StoreEstateSettings(dbSettings);
296 response = String.Empty;
297
298 // make sure there's a log entry to document the change
299 m_log.InfoFormat("[ESTATE]: Estate {0} renamed from \"{1}\" to \"{2}\"", estateID, oldName, newName);
300
301 // propagate the change
302 List<UUID> regions = Scene.GetEstateRegions(estateID);
303 UUID regionId = (regions.Count() > 0) ? regions.ElementAt(0) : UUID.Zero;
304 if (regionId != UUID.Zero)
305 {
306 ChangeDelegate change = OnEstateInfoChange;
307
308 if (change != null)
309 change(regionId);
310 }
311 }
312 }
313 return response;
314 }
315
316 public string SetRegionEstate(RegionInfo regionInfo, int estateID)
317 {
318 string response;
319
320 if (regionInfo.EstateSettings.EstateID == estateID)
321 {
322 response = String.Format("\"{0}\" is already part of estate {1}", regionInfo.RegionName, estateID);
323 }
324 else
325 {
326 // get the current settings from DB
327 EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
328 if (dbSettings.EstateID == 0)
329 {
330 response = String.Format("No estate found with ID {0}", estateID);
331 }
332 else if (Scene.EstateDataService.LinkRegion(regionInfo.RegionID, estateID))
333 {
334 // make sure there's a log entry to document the change
335 m_log.InfoFormat("[ESTATE]: Region {0} ({1}) moved to Estate {2} ({3}).", regionInfo.RegionID, regionInfo.RegionName, estateID, dbSettings.EstateName);
336
337 // propagate the change
338 ChangeDelegate change = OnEstateInfoChange;
339
340 if (change != null)
341 change(regionInfo.RegionID);
342
343 response = String.Empty;
344 }
345 else
346 {
347 response = String.Format("Could not move \"{0}\" to estate {1}", regionInfo.RegionName, estateID);
348 }
349 }
350 return response;
351 }
352
353 public string CreateEstate(string estateName, UUID ownerID)
354 {
355 string response;
356 if (string.IsNullOrEmpty(estateName))
357 {
358 response = "No estate name specified.";
359 }
360 else
361 {
362 List<int> estates = Scene.EstateDataService.GetEstates(estateName);
363 if (estates.Count() > 0)
364 {
365 response = String.Format("An estate named \"{0}\" already exists.", estateName);
366 }
367 else
368 {
369 EstateSettings settings = Scene.EstateDataService.CreateNewEstate();
370 if (settings == null)
371 response = String.Format("Unable to create estate \"{0}\" at this simulator", estateName);
372 else
373 {
374 settings.EstateOwner = ownerID;
375 settings.EstateName = estateName;
376 Scene.EstateDataService.StoreEstateSettings(settings);
377 response = String.Empty;
378 }
379 }
380 }
381 return response;
382 }
383
384 #endregion
385
115 #region Packet Data Responders 386 #region Packet Data Responders
116 387
388 private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice)
389 {
390 sendDetailedEstateData(remote_client, invoice);
391 sendEstateLists(remote_client, invoice);
392 }
393
117 private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice) 394 private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice)
118 { 395 {
119 uint sun = 0; 396 uint sun = 0;
120 397
121 if (!Scene.RegionInfo.EstateSettings.UseGlobalTime) 398 if (Scene.RegionInfo.EstateSettings.FixedSun)
122 sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800; 399 sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800;
123 UUID estateOwner; 400 UUID estateOwner;
124 estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner; 401 estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner;
@@ -136,7 +413,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
136 (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime, 413 (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime,
137 Scene.RegionInfo.EstateSettings.AbuseEmail, 414 Scene.RegionInfo.EstateSettings.AbuseEmail,
138 estateOwner); 415 estateOwner);
416 }
139 417
418 private void sendEstateLists(IClientAPI remote_client, UUID invoice)
419 {
140 remote_client.SendEstateList(invoice, 420 remote_client.SendEstateList(invoice,
141 (int)Constants.EstateAccessCodex.EstateManagers, 421 (int)Constants.EstateAccessCodex.EstateManagers,
142 Scene.RegionInfo.EstateSettings.EstateManagers, 422 Scene.RegionInfo.EstateSettings.EstateManagers,
@@ -210,12 +490,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
210 sendRegionInfoPacketToAll(); 490 sendRegionInfoPacketToAll();
211 } 491 }
212 492
213 public void setEstateTerrainBaseTexture(int level, UUID texture)
214 {
215 setEstateTerrainBaseTexture(null, level, texture);
216 sendRegionHandshakeToAll();
217 }
218
219 public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int level, UUID texture) 493 public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int level, UUID texture)
220 { 494 {
221 if (texture == UUID.Zero) 495 if (texture == UUID.Zero)
@@ -242,11 +516,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
242 sendRegionInfoPacketToAll(); 516 sendRegionInfoPacketToAll();
243 } 517 }
244 518
245 public void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue)
246 {
247 setEstateTerrainTextureHeights(null, corner, lowValue, highValue);
248 }
249
250 public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue) 519 public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue)
251 { 520 {
252 switch (corner) 521 switch (corner)
@@ -330,7 +599,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
330 timeInSeconds -= 15; 599 timeInSeconds -= 15;
331 } 600 }
332 601
333 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); 602 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false);
334 603
335 m_log.InfoFormat( 604 m_log.InfoFormat(
336 "User {0} requested restart of region {1} in {2} seconds", 605 "User {0} requested restart of region {1} in {2} seconds",
@@ -372,13 +641,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
372 { 641 {
373 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 642 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
374 estateSettings.AddEstateUser(user); 643 estateSettings.AddEstateUser(user);
375 estateSettings.Save(); 644 Scene.EstateDataService.StoreEstateSettings(estateSettings);
376 } 645 }
377 } 646 }
378 } 647 }
379 648
380 Scene.RegionInfo.EstateSettings.AddEstateUser(user); 649 Scene.RegionInfo.EstateSettings.AddEstateUser(user);
381 Scene.RegionInfo.EstateSettings.Save(); 650 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
382 651
383 TriggerEstateInfoChange(); 652 TriggerEstateInfoChange();
384 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); 653 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID);
@@ -405,13 +674,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
405 { 674 {
406 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 675 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
407 estateSettings.RemoveEstateUser(user); 676 estateSettings.RemoveEstateUser(user);
408 estateSettings.Save(); 677 Scene.EstateDataService.StoreEstateSettings(estateSettings);
409 } 678 }
410 } 679 }
411 } 680 }
412 681
413 Scene.RegionInfo.EstateSettings.RemoveEstateUser(user); 682 Scene.RegionInfo.EstateSettings.RemoveEstateUser(user);
414 Scene.RegionInfo.EstateSettings.Save(); 683 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
415 684
416 TriggerEstateInfoChange(); 685 TriggerEstateInfoChange();
417 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); 686 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID);
@@ -437,13 +706,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
437 { 706 {
438 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 707 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
439 estateSettings.AddEstateGroup(user); 708 estateSettings.AddEstateGroup(user);
440 estateSettings.Save(); 709 Scene.EstateDataService.StoreEstateSettings(estateSettings);
441 } 710 }
442 } 711 }
443 } 712 }
444 713
445 Scene.RegionInfo.EstateSettings.AddEstateGroup(user); 714 Scene.RegionInfo.EstateSettings.AddEstateGroup(user);
446 Scene.RegionInfo.EstateSettings.Save(); 715 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
447 716
448 TriggerEstateInfoChange(); 717 TriggerEstateInfoChange();
449 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); 718 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID);
@@ -469,13 +738,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
469 { 738 {
470 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 739 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
471 estateSettings.RemoveEstateGroup(user); 740 estateSettings.RemoveEstateGroup(user);
472 estateSettings.Save(); 741 Scene.EstateDataService.StoreEstateSettings(estateSettings);
473 } 742 }
474 } 743 }
475 } 744 }
476 745
477 Scene.RegionInfo.EstateSettings.RemoveEstateGroup(user); 746 Scene.RegionInfo.EstateSettings.RemoveEstateGroup(user);
478 Scene.RegionInfo.EstateSettings.Save(); 747 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
479 748
480 TriggerEstateInfoChange(); 749 TriggerEstateInfoChange();
481 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); 750 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID);
@@ -524,7 +793,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
524 793
525 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 794 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
526 estateSettings.AddBan(bitem); 795 estateSettings.AddBan(bitem);
527 estateSettings.Save(); 796 Scene.EstateDataService.StoreEstateSettings(estateSettings);
528 } 797 }
529 } 798 }
530 } 799 }
@@ -537,7 +806,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
537 item.BannedHostIPMask = "0.0.0.0"; 806 item.BannedHostIPMask = "0.0.0.0";
538 807
539 Scene.RegionInfo.EstateSettings.AddBan(item); 808 Scene.RegionInfo.EstateSettings.AddBan(item);
540 Scene.RegionInfo.EstateSettings.Save(); 809 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
541 810
542 TriggerEstateInfoChange(); 811 TriggerEstateInfoChange();
543 812
@@ -546,7 +815,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
546 { 815 {
547 if (!s.IsChildAgent) 816 if (!s.IsChildAgent)
548 { 817 {
549 Scene.TeleportClientHome(user, s.ControllingClient); 818 if (!Scene.TeleportClientHome(user, s.ControllingClient))
819 {
820 s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
821 Scene.CloseAgent(s.UUID, false);
822 }
550 } 823 }
551 } 824 }
552 825
@@ -555,7 +828,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
555 { 828 {
556 remote_client.SendAlertMessage("User is already on the region ban list"); 829 remote_client.SendAlertMessage("User is already on the region ban list");
557 } 830 }
558 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 831 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
559 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 832 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
560 } 833 }
561 else 834 else
@@ -596,13 +869,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
596 { 869 {
597 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 870 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
598 estateSettings.RemoveBan(user); 871 estateSettings.RemoveBan(user);
599 estateSettings.Save(); 872 Scene.EstateDataService.StoreEstateSettings(estateSettings);
600 } 873 }
601 } 874 }
602 } 875 }
603 876
604 Scene.RegionInfo.EstateSettings.RemoveBan(listitem.BannedUserID); 877 Scene.RegionInfo.EstateSettings.RemoveBan(listitem.BannedUserID);
605 Scene.RegionInfo.EstateSettings.Save(); 878 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
606 879
607 TriggerEstateInfoChange(); 880 TriggerEstateInfoChange();
608 } 881 }
@@ -611,7 +884,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
611 remote_client.SendAlertMessage("User is not on the region ban list"); 884 remote_client.SendAlertMessage("User is not on the region ban list");
612 } 885 }
613 886
614 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 887 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
615 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 888 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
616 } 889 }
617 else 890 else
@@ -635,13 +908,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
635 { 908 {
636 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 909 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
637 estateSettings.AddEstateManager(user); 910 estateSettings.AddEstateManager(user);
638 estateSettings.Save(); 911 Scene.EstateDataService.StoreEstateSettings(estateSettings);
639 } 912 }
640 } 913 }
641 } 914 }
642 915
643 Scene.RegionInfo.EstateSettings.AddEstateManager(user); 916 Scene.RegionInfo.EstateSettings.AddEstateManager(user);
644 Scene.RegionInfo.EstateSettings.Save(); 917 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
645 918
646 TriggerEstateInfoChange(); 919 TriggerEstateInfoChange();
647 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); 920 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID);
@@ -667,13 +940,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
667 { 940 {
668 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 941 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
669 estateSettings.RemoveEstateManager(user); 942 estateSettings.RemoveEstateManager(user);
670 estateSettings.Save(); 943 Scene.EstateDataService.StoreEstateSettings(estateSettings);
671 } 944 }
672 } 945 }
673 } 946 }
674 947
675 Scene.RegionInfo.EstateSettings.RemoveEstateManager(user); 948 Scene.RegionInfo.EstateSettings.RemoveEstateManager(user);
676 Scene.RegionInfo.EstateSettings.Save(); 949 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
677 950
678 TriggerEstateInfoChange(); 951 TriggerEstateInfoChange();
679 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); 952 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID);
@@ -685,7 +958,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
685 } 958 }
686 } 959 }
687 960
688 public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) 961 public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
689 { 962 {
690 SceneObjectPart part; 963 SceneObjectPart part;
691 964
@@ -725,7 +998,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
725 default: 998 default:
726 break; 999 break;
727 } 1000 }
728 SendTelehubInfo(client); 1001
1002 if (client != null)
1003 SendTelehubInfo(client);
729 } 1004 }
730 1005
731 private void SendSimulatorBlueBoxMessage( 1006 private void SendSimulatorBlueBoxMessage(
@@ -777,7 +1052,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
777 ScenePresence s = Scene.GetScenePresence(prey); 1052 ScenePresence s = Scene.GetScenePresence(prey);
778 if (s != null) 1053 if (s != null)
779 { 1054 {
780 Scene.TeleportClientHome(prey, s.ControllingClient); 1055 if (!Scene.TeleportClientHome(prey, s.ControllingClient))
1056 {
1057 s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
1058 Scene.CloseAgent(s.UUID, false);
1059 }
781 } 1060 }
782 } 1061 }
783 } 1062 }
@@ -795,33 +1074,36 @@ namespace OpenSim.Region.CoreModules.World.Estate
795 // Also make sure they are actually in the region 1074 // Also make sure they are actually in the region
796 ScenePresence p; 1075 ScenePresence p;
797 if(Scene.TryGetScenePresence(client.AgentId, out p)) 1076 if(Scene.TryGetScenePresence(client.AgentId, out p))
798 Scene.TeleportClientHome(p.UUID, p.ControllingClient); 1077 {
1078 if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
1079 {
1080 p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
1081 Scene.CloseAgent(p.UUID, false);
1082 }
1083 }
799 } 1084 }
800 }); 1085 });
801 } 1086 }
802 1087
803 private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID) 1088 private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID)
804 { 1089 {
805 if (TerrainUploader != null) 1090 lock (this)
806 { 1091 {
807 lock (TerrainUploader) 1092 if ((TerrainUploader != null) && (XferID == TerrainUploader.XferID))
808 { 1093 {
809 if (XferID == TerrainUploader.XferID) 1094 remoteClient.OnXferReceive -= TerrainUploader.XferReceive;
810 { 1095 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
811 remoteClient.OnXferReceive -= TerrainUploader.XferReceive; 1096 TerrainUploader.TerrainUploadDone -= HandleTerrainApplication;
812 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
813 TerrainUploader.TerrainUploadDone -= HandleTerrainApplication;
814 1097
815 TerrainUploader = null; 1098 TerrainUploader = null;
816 remoteClient.SendAlertMessage("Terrain Upload aborted by the client"); 1099 remoteClient.SendAlertMessage("Terrain Upload aborted by the client");
817 }
818 } 1100 }
819 } 1101 }
820
821 } 1102 }
1103
822 private void HandleTerrainApplication(string filename, byte[] terrainData, IClientAPI remoteClient) 1104 private void HandleTerrainApplication(string filename, byte[] terrainData, IClientAPI remoteClient)
823 { 1105 {
824 lock (TerrainUploader) 1106 lock (this)
825 { 1107 {
826 remoteClient.OnXferReceive -= TerrainUploader.XferReceive; 1108 remoteClient.OnXferReceive -= TerrainUploader.XferReceive;
827 remoteClient.OnAbortXfer -= AbortTerrainXferHandler; 1109 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
@@ -829,18 +1111,18 @@ namespace OpenSim.Region.CoreModules.World.Estate
829 1111
830 TerrainUploader = null; 1112 TerrainUploader = null;
831 } 1113 }
1114
1115 m_log.DebugFormat("[CLIENT]: Terrain upload from {0} to {1} complete.", remoteClient.Name, Scene.Name);
832 remoteClient.SendAlertMessage("Terrain Upload Complete. Loading...."); 1116 remoteClient.SendAlertMessage("Terrain Upload Complete. Loading....");
1117
833 ITerrainModule terr = Scene.RequestModuleInterface<ITerrainModule>(); 1118 ITerrainModule terr = Scene.RequestModuleInterface<ITerrainModule>();
834 1119
835 if (terr != null) 1120 if (terr != null)
836 { 1121 {
837 m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName);
838
839 try 1122 try
840 { 1123 {
841 MemoryStream terrainStream = new MemoryStream(terrainData); 1124 using (MemoryStream terrainStream = new MemoryStream(terrainData))
842 terr.LoadFromStream(filename, terrainStream); 1125 terr.LoadFromStream(filename, terrainStream);
843 terrainStream.Close();
844 1126
845 FileInfo x = new FileInfo(filename); 1127 FileInfo x = new FileInfo(filename);
846 remoteClient.SendAlertMessage("Your terrain was loaded as a " + x.Extension + " file. It may take a few moments to appear."); 1128 remoteClient.SendAlertMessage("Your terrain was loaded as a " + x.Extension + " file. It may take a few moments to appear.");
@@ -880,25 +1162,27 @@ namespace OpenSim.Region.CoreModules.World.Estate
880 1162
881 private void handleUploadTerrain(IClientAPI remote_client, string clientFileName) 1163 private void handleUploadTerrain(IClientAPI remote_client, string clientFileName)
882 { 1164 {
883 if (TerrainUploader == null) 1165 lock (this)
884 { 1166 {
885 1167 if (TerrainUploader == null)
886 TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName);
887 lock (TerrainUploader)
888 { 1168 {
1169 m_log.DebugFormat(
1170 "[TERRAIN]: Started receiving terrain upload for region {0} from {1}",
1171 Scene.Name, remote_client.Name);
1172
1173 TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName);
889 remote_client.OnXferReceive += TerrainUploader.XferReceive; 1174 remote_client.OnXferReceive += TerrainUploader.XferReceive;
890 remote_client.OnAbortXfer += AbortTerrainXferHandler; 1175 remote_client.OnAbortXfer += AbortTerrainXferHandler;
891 TerrainUploader.TerrainUploadDone += HandleTerrainApplication; 1176 TerrainUploader.TerrainUploadDone += HandleTerrainApplication;
1177 TerrainUploader.RequestStartXfer(remote_client);
1178 }
1179 else
1180 {
1181 remote_client.SendAlertMessage("Another Terrain Upload is in progress. Please wait your turn!");
892 } 1182 }
893 TerrainUploader.RequestStartXfer(remote_client);
894
895 }
896 else
897 {
898 remote_client.SendAlertMessage("Another Terrain Upload is in progress. Please wait your turn!");
899 } 1183 }
900 } 1184 }
901 1185
902 private void handleTerrainRequest(IClientAPI remote_client, string clientFileName) 1186 private void handleTerrainRequest(IClientAPI remote_client, string clientFileName)
903 { 1187 {
904 // Save terrain here 1188 // Save terrain here
@@ -906,7 +1190,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
906 1190
907 if (terr != null) 1191 if (terr != null)
908 { 1192 {
909 m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName); 1193// m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName);
910 if (File.Exists(Util.dataDir() + "/terrain.raw")) 1194 if (File.Exists(Util.dataDir() + "/terrain.raw"))
911 { 1195 {
912 File.Delete(Util.dataDir() + "/terrain.raw"); 1196 File.Delete(Util.dataDir() + "/terrain.raw");
@@ -918,8 +1202,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
918 input.Read(bdata, 0, (int)input.Length); 1202 input.Read(bdata, 0, (int)input.Length);
919 remote_client.SendAlertMessage("Terrain file written, starting download..."); 1203 remote_client.SendAlertMessage("Terrain file written, starting download...");
920 Scene.XferManager.AddNewFile("terrain.raw", bdata); 1204 Scene.XferManager.AddNewFile("terrain.raw", bdata);
921 // Tell client about it 1205
922 m_log.Warn("[CLIENT]: Sending Terrain to " + remote_client.Name); 1206 m_log.DebugFormat("[CLIENT]: Sending terrain for region {0} to {1}", Scene.Name, remote_client.Name);
1207
923 remote_client.SendInitiateDownload("terrain.raw", clientFileName); 1208 remote_client.SendInitiateDownload("terrain.raw", clientFileName);
924 } 1209 }
925 } 1210 }
@@ -1080,11 +1365,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
1080 remoteClient.SendRegionHandshake(Scene.RegionInfo,args); 1365 remoteClient.SendRegionHandshake(Scene.RegionInfo,args);
1081 } 1366 }
1082 1367
1083 public void sendRegionHandshakeToAll()
1084 {
1085 Scene.ForEachClient(sendRegionHandshake);
1086 }
1087
1088 public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2) 1368 public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2)
1089 { 1369 {
1090 if (parms2 == 0) 1370 if (parms2 == 0)
@@ -1096,6 +1376,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1096 { 1376 {
1097 Scene.RegionInfo.EstateSettings.UseGlobalTime = false; 1377 Scene.RegionInfo.EstateSettings.UseGlobalTime = false;
1098 Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0; 1378 Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0;
1379 // Warning: FixedSun should be set to True, otherwise this sun position won't be used.
1099 } 1380 }
1100 1381
1101 if ((parms1 & 0x00000010) != 0) 1382 if ((parms1 & 0x00000010) != 0)
@@ -1138,7 +1419,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1138 else 1419 else
1139 Scene.RegionInfo.EstateSettings.DenyMinors = false; 1420 Scene.RegionInfo.EstateSettings.DenyMinors = false;
1140 1421
1141 Scene.RegionInfo.EstateSettings.Save(); 1422 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
1142 TriggerEstateInfoChange(); 1423 TriggerEstateInfoChange();
1143 1424
1144 Scene.TriggerEstateSunUpdate(); 1425 Scene.TriggerEstateSunUpdate();
@@ -1165,11 +1446,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1165 sendRegionInfoPacketToAll(); 1446 sendRegionInfoPacketToAll();
1166 } 1447 }
1167 1448
1168 #endregion 1449
1450 #endregion
1169 1451
1170 private void EventManager_OnNewClient(IClientAPI client) 1452 private void EventManager_OnNewClient(IClientAPI client)
1171 { 1453 {
1172 client.OnDetailedEstateDataRequest += sendDetailedEstateData; 1454 client.OnDetailedEstateDataRequest += clientSendDetailedEstateData;
1173 client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler; 1455 client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler;
1174// client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture; 1456// client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture;
1175 client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture; 1457 client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture;
@@ -1179,7 +1461,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1179 client.OnEstateRestartSimRequest += handleEstateRestartSimRequest; 1461 client.OnEstateRestartSimRequest += handleEstateRestartSimRequest;
1180 client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest; 1462 client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest;
1181 client.OnEstateChangeInfo += handleEstateChangeInfo; 1463 client.OnEstateChangeInfo += handleEstateChangeInfo;
1182 client.OnEstateManageTelehub += handleOnEstateManageTelehub; 1464 client.OnEstateManageTelehub += HandleOnEstateManageTelehub;
1183 client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest; 1465 client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest;
1184 client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage; 1466 client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage;
1185 client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage; 1467 client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage;
@@ -1195,56 +1477,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1195 sendRegionHandshake(client); 1477 sendRegionHandshake(client);
1196 } 1478 }
1197 1479
1198 public uint GetRegionFlags() 1480 private uint GetEstateFlags()
1199 {
1200 RegionFlags flags = RegionFlags.None;
1201
1202 // Fully implemented
1203 //
1204 if (Scene.RegionInfo.RegionSettings.AllowDamage)
1205 flags |= RegionFlags.AllowDamage;
1206 if (Scene.RegionInfo.RegionSettings.BlockTerraform)
1207 flags |= RegionFlags.BlockTerraform;
1208 if (!Scene.RegionInfo.RegionSettings.AllowLandResell)
1209 flags |= RegionFlags.BlockLandResell;
1210 if (Scene.RegionInfo.RegionSettings.DisableCollisions)
1211 flags |= RegionFlags.SkipCollisions;
1212 if (Scene.RegionInfo.RegionSettings.DisableScripts)
1213 flags |= RegionFlags.SkipScripts;
1214 if (Scene.RegionInfo.RegionSettings.DisablePhysics)
1215 flags |= RegionFlags.SkipPhysics;
1216 if (Scene.RegionInfo.RegionSettings.BlockFly)
1217 flags |= RegionFlags.NoFly;
1218 if (Scene.RegionInfo.RegionSettings.RestrictPushing)
1219 flags |= RegionFlags.RestrictPushObject;
1220 if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide)
1221 flags |= RegionFlags.AllowParcelChanges;
1222 if (Scene.RegionInfo.RegionSettings.BlockShowInSearch)
1223 flags |= RegionFlags.BlockParcelSearch;
1224
1225 if (Scene.RegionInfo.RegionSettings.FixedSun)
1226 flags |= RegionFlags.SunFixed;
1227 if (Scene.RegionInfo.RegionSettings.Sandbox)
1228 flags |= RegionFlags.Sandbox;
1229 if (Scene.RegionInfo.EstateSettings.AllowVoice)
1230 flags |= RegionFlags.AllowVoice;
1231
1232 // Fudge these to always on, so the menu options activate
1233 //
1234 flags |= RegionFlags.AllowLandmark;
1235 flags |= RegionFlags.AllowSetHome;
1236
1237 // TODO: SkipUpdateInterestList
1238
1239 // Omitted
1240 //
1241 // Omitted: NullLayer (what is that?)
1242 // Omitted: SkipAgentAction (what does it do?)
1243
1244 return (uint)flags;
1245 }
1246
1247 public uint GetEstateFlags()
1248 { 1481 {
1249 RegionFlags flags = RegionFlags.None; 1482 RegionFlags flags = RegionFlags.None;
1250 1483
@@ -1273,40 +1506,18 @@ namespace OpenSim.Region.CoreModules.World.Estate
1273 flags |= RegionFlags.ResetHomeOnTeleport; 1506 flags |= RegionFlags.ResetHomeOnTeleport;
1274 if (Scene.RegionInfo.EstateSettings.TaxFree) 1507 if (Scene.RegionInfo.EstateSettings.TaxFree)
1275 flags |= RegionFlags.TaxFree; 1508 flags |= RegionFlags.TaxFree;
1509 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
1510 flags |= RegionFlags.AllowLandmark;
1511 if (Scene.RegionInfo.EstateSettings.AllowParcelChanges)
1512 flags |= RegionFlags.AllowParcelChanges;
1513 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
1514 flags |= RegionFlags.AllowSetHome;
1276 if (Scene.RegionInfo.EstateSettings.DenyMinors) 1515 if (Scene.RegionInfo.EstateSettings.DenyMinors)
1277 flags |= (RegionFlags)(1 << 30); 1516 flags |= (RegionFlags)(1 << 30);
1278 1517
1279 return (uint)flags; 1518 return (uint)flags;
1280 } 1519 }
1281 1520
1282 public bool IsManager(UUID avatarID)
1283 {
1284 if (avatarID == Scene.RegionInfo.EstateSettings.EstateOwner)
1285 return true;
1286
1287 List<UUID> ems = new List<UUID>(Scene.RegionInfo.EstateSettings.EstateManagers);
1288 if (ems.Contains(avatarID))
1289 return true;
1290
1291 return false;
1292 }
1293
1294 public void TriggerRegionInfoChange()
1295 {
1296 ChangeDelegate change = OnRegionInfoChange;
1297
1298 if (change != null)
1299 change(Scene.RegionInfo.RegionID);
1300 }
1301
1302 public void TriggerEstateInfoChange()
1303 {
1304 ChangeDelegate change = OnEstateInfoChange;
1305
1306 if (change != null)
1307 change(Scene.RegionInfo.RegionID);
1308 }
1309
1310 public void TriggerEstateMessage(UUID fromID, string fromName, string message) 1521 public void TriggerEstateMessage(UUID fromID, string fromName, string message)
1311 { 1522 {
1312 MessageDelegate onmessage = OnEstateMessage; 1523 MessageDelegate onmessage = OnEstateMessage;
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
index b8d8b10..2d74eaf 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
@@ -78,7 +78,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
78 /// <param name="data"></param> 78 /// <param name="data"></param>
79 public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) 79 public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data)
80 { 80 {
81 if (mXferID == xferID) 81 if (mXferID != xferID)
82 return;
83
84 lock (this)
82 { 85 {
83 if (m_asset.Data.Length > 1) 86 if (m_asset.Data.Length > 1)
84 { 87 {
@@ -99,7 +102,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
99 if ((packetID & 0x80000000) != 0) 102 if ((packetID & 0x80000000) != 0)
100 { 103 {
101 SendCompleteMessage(remoteClient); 104 SendCompleteMessage(remoteClient);
102
103 } 105 }
104 } 106 }
105 } 107 }
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs
new file mode 100644
index 0000000..73e706c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs
@@ -0,0 +1,218 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31
32using OpenSim.Services.Interfaces;
33using GridRegion = OpenSim.Services.Interfaces.GridRegion;
34using OpenSim.Server.Base;
35using OpenSim.Framework.Servers.HttpServer;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Scenes;
38
39using OpenMetaverse;
40using log4net;
41
42namespace OpenSim.Region.CoreModules.World.Estate
43{
44 public class EstateConnector
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 protected XEstateModule m_EstateModule;
49
50 public EstateConnector(XEstateModule module)
51 {
52 m_EstateModule = module;
53 }
54
55 public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID)
56 {
57 Dictionary<string, object> sendData = new Dictionary<string, object>();
58 sendData["METHOD"] = "teleport_home_one_user";
59
60 sendData["EstateID"] = EstateID.ToString();
61 sendData["PreyID"] = PreyID.ToString();
62
63 SendToEstate(EstateID, sendData);
64 }
65
66 public void SendTeleportHomeAllUsers(uint EstateID)
67 {
68 Dictionary<string, object> sendData = new Dictionary<string, object>();
69 sendData["METHOD"] = "teleport_home_all_users";
70
71 sendData["EstateID"] = EstateID.ToString();
72
73 SendToEstate(EstateID, sendData);
74 }
75
76 public bool SendUpdateCovenant(uint EstateID, UUID CovenantID)
77 {
78 Dictionary<string, object> sendData = new Dictionary<string, object>();
79 sendData["METHOD"] = "update_covenant";
80
81 sendData["CovenantID"] = CovenantID.ToString();
82 sendData["EstateID"] = EstateID.ToString();
83
84 // Handle local regions locally
85 //
86 foreach (Scene s in m_EstateModule.Scenes)
87 {
88 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
89 s.RegionInfo.RegionSettings.Covenant = CovenantID;
90// s.ReloadEstateData();
91 }
92
93 SendToEstate(EstateID, sendData);
94
95 return true;
96 }
97
98 public bool SendUpdateEstate(uint EstateID)
99 {
100 Dictionary<string, object> sendData = new Dictionary<string, object>();
101 sendData["METHOD"] = "update_estate";
102
103 sendData["EstateID"] = EstateID.ToString();
104
105 // Handle local regions locally
106 //
107 foreach (Scene s in m_EstateModule.Scenes)
108 {
109 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
110 s.ReloadEstateData();
111 }
112
113 SendToEstate(EstateID, sendData);
114
115 return true;
116 }
117
118 public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message)
119 {
120 Dictionary<string, object> sendData = new Dictionary<string, object>();
121 sendData["METHOD"] = "estate_message";
122
123 sendData["EstateID"] = EstateID.ToString();
124 sendData["FromID"] = FromID.ToString();
125 sendData["FromName"] = FromName;
126 sendData["Message"] = Message;
127
128 SendToEstate(EstateID, sendData);
129 }
130
131 private void SendToEstate(uint EstateID, Dictionary<string, object> sendData)
132 {
133 List<UUID> regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID);
134
135 UUID ScopeID = UUID.Zero;
136
137 // Handle local regions locally
138 //
139 lock (m_EstateModule.Scenes)
140 {
141 foreach (Scene s in m_EstateModule.Scenes)
142 {
143 if (regions.Contains(s.RegionInfo.RegionID))
144 {
145 // All regions in one estate are in the same scope.
146 // Use that scope.
147 //
148 ScopeID = s.RegionInfo.ScopeID;
149 regions.Remove(s.RegionInfo.RegionID);
150 }
151 }
152 }
153
154 // Our own region should always be in the above list.
155 // In a standalone this would not be true. But then,
156 // Scope ID is not relevat there. Use first scope.
157 //
158 if (ScopeID == UUID.Zero)
159 ScopeID = m_EstateModule.Scenes[0].RegionInfo.ScopeID;
160
161 // Don't send to the same instance twice
162 //
163 List<string> done = new List<string>();
164
165 // Send to remote regions
166 //
167 foreach (UUID regionID in regions)
168 {
169 GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID);
170 if (region != null)
171 {
172 string url = "http://" + region.ExternalHostName + ":" + region.HttpPort;
173 if (done.Contains(url))
174 continue;
175
176 Call(region, sendData);
177 done.Add(url);
178 }
179 }
180 }
181
182 private bool Call(GridRegion region, Dictionary<string, object> sendData)
183 {
184 string reqString = ServerUtils.BuildQueryString(sendData);
185 // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString);
186 try
187 {
188 string url = "http://" + region.ExternalHostName + ":" + region.HttpPort;
189 string reply = SynchronousRestFormsRequester.MakeRequest("POST",
190 url + "/estate",
191 reqString);
192 if (reply != string.Empty)
193 {
194 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
195
196 if (replyData.ContainsKey("RESULT"))
197 {
198 if (replyData["RESULT"].ToString().ToLower() == "true")
199 return true;
200 else
201 return false;
202 }
203 else
204 m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field");
205
206 }
207 else
208 m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply");
209 }
210 catch (Exception e)
211 {
212 m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message);
213 }
214
215 return false;
216 }
217 }
218}
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs
new file mode 100644
index 0000000..4bb3799
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs
@@ -0,0 +1,255 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40using OpenSim.Server.Base;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using Mono.Addins;
44
45namespace OpenSim.Region.CoreModules.World.Estate
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")]
48 public class XEstateModule : ISharedRegionModule
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 protected List<Scene> m_Scenes = new List<Scene>();
53 protected bool m_InInfoUpdate = false;
54
55 public bool InInfoUpdate
56 {
57 get { return m_InInfoUpdate; }
58 set { m_InInfoUpdate = value; }
59 }
60
61 public List<Scene> Scenes
62 {
63 get { return m_Scenes; }
64 }
65
66 protected EstateConnector m_EstateConnector;
67
68 public void Initialise(IConfigSource config)
69 {
70 int port = 0;
71
72 IConfig estateConfig = config.Configs["Estate"];
73 if (estateConfig != null)
74 {
75 port = estateConfig.GetInt("Port", 0);
76 }
77
78 m_EstateConnector = new EstateConnector(this);
79
80 // Instantiate the request handler
81 IHttpServer server = MainServer.GetHttpServer((uint)port);
82 server.AddStreamHandler(new EstateRequestHandler(this));
83 }
84
85 public void PostInitialise()
86 {
87 }
88
89 public void Close()
90 {
91 }
92
93 public void AddRegion(Scene scene)
94 {
95 lock (m_Scenes)
96 m_Scenes.Add(scene);
97
98 scene.EventManager.OnNewClient += OnNewClient;
99 }
100
101 public void RegionLoaded(Scene scene)
102 {
103 IEstateModule em = scene.RequestModuleInterface<IEstateModule>();
104
105 em.OnRegionInfoChange += OnRegionInfoChange;
106 em.OnEstateInfoChange += OnEstateInfoChange;
107 em.OnEstateMessage += OnEstateMessage;
108 }
109
110 public void RemoveRegion(Scene scene)
111 {
112 scene.EventManager.OnNewClient -= OnNewClient;
113
114 lock (m_Scenes)
115 m_Scenes.Remove(scene);
116 }
117
118 public string Name
119 {
120 get { return "EstateModule"; }
121 }
122
123 public Type ReplaceableInterface
124 {
125 get { return null; }
126 }
127
128 private Scene FindScene(UUID RegionID)
129 {
130 foreach (Scene s in Scenes)
131 {
132 if (s.RegionInfo.RegionID == RegionID)
133 return s;
134 }
135
136 return null;
137 }
138
139 private void OnRegionInfoChange(UUID RegionID)
140 {
141 Scene s = FindScene(RegionID);
142 if (s == null)
143 return;
144
145 if (!m_InInfoUpdate)
146 m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant);
147 }
148
149 private void OnEstateInfoChange(UUID RegionID)
150 {
151 Scene s = FindScene(RegionID);
152 if (s == null)
153 return;
154
155 if (!m_InInfoUpdate)
156 m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID);
157 }
158
159 private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message)
160 {
161 Scene senderScenes = FindScene(RegionID);
162 if (senderScenes == null)
163 return;
164
165 uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID;
166
167 foreach (Scene s in Scenes)
168 {
169 if (s.RegionInfo.EstateSettings.EstateID == estateID)
170 {
171 IDialogModule dm = s.RequestModuleInterface<IDialogModule>();
172
173 if (dm != null)
174 {
175 dm.SendNotificationToUsersInRegion(FromID, FromName,
176 Message);
177 }
178 }
179 }
180 if (!m_InInfoUpdate)
181 m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message);
182 }
183
184 private void OnNewClient(IClientAPI client)
185 {
186 client.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest;
187 client.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest;
188
189 }
190
191 private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey)
192 {
193 if (prey == UUID.Zero)
194 return;
195
196 if (!(client.Scene is Scene))
197 return;
198
199 Scene scene = (Scene)client.Scene;
200
201 uint estateID = scene.RegionInfo.EstateSettings.EstateID;
202
203 if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false))
204 return;
205
206 foreach (Scene s in Scenes)
207 {
208 if (s == scene)
209 continue; // Already handles by estate module
210 if (s.RegionInfo.EstateSettings.EstateID != estateID)
211 continue;
212
213 ScenePresence p = scene.GetScenePresence(prey);
214 if (p != null && !p.IsChildAgent)
215 {
216 p.ControllingClient.SendTeleportStart(16);
217 scene.TeleportClientHome(prey, p.ControllingClient);
218 }
219 }
220
221 m_EstateConnector.SendTeleportHomeOneUser(estateID, prey);
222 }
223
224 private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID)
225 {
226 if (!(client.Scene is Scene))
227 return;
228
229 Scene scene = (Scene)client.Scene;
230
231 uint estateID = scene.RegionInfo.EstateSettings.EstateID;
232
233 if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false))
234 return;
235
236 foreach (Scene s in Scenes)
237 {
238 if (s == scene)
239 continue; // Already handles by estate module
240 if (s.RegionInfo.EstateSettings.EstateID != estateID)
241 continue;
242
243 scene.ForEachScenePresence(delegate(ScenePresence p) {
244 if (p != null && !p.IsChildAgent)
245 {
246 p.ControllingClient.SendTeleportStart(16);
247 scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient);
248 }
249 });
250 }
251
252 m_EstateConnector.SendTeleportHomeAllUsers(estateID);
253 }
254 }
255}
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs
new file mode 100644
index 0000000..ec5af2b
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs
@@ -0,0 +1,288 @@
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
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Framework.Interfaces;
39
40using OpenMetaverse;
41using log4net;
42
43namespace OpenSim.Region.CoreModules.World.Estate
44{
45 public class EstateRequestHandler : BaseStreamHandler
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 protected XEstateModule m_EstateModule;
50 protected Object m_RequestLock = new Object();
51
52 public EstateRequestHandler(XEstateModule fmodule)
53 : base("POST", "/estate")
54 {
55 m_EstateModule = fmodule;
56 }
57
58 protected override byte[] ProcessRequest(string path, Stream requestData,
59 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
60 {
61 StreamReader sr = new StreamReader(requestData);
62 string body = sr.ReadToEnd();
63 sr.Close();
64 body = body.Trim();
65
66 m_log.DebugFormat("[XESTATE HANDLER]: query String: {0}", body);
67
68 try
69 {
70 lock (m_RequestLock)
71 {
72 Dictionary<string, object> request =
73 ServerUtils.ParseQueryString(body);
74
75 if (!request.ContainsKey("METHOD"))
76 return FailureResult();
77
78 string method = request["METHOD"].ToString();
79 request.Remove("METHOD");
80
81 try
82 {
83 m_EstateModule.InInfoUpdate = false;
84
85 switch (method)
86 {
87 case "update_covenant":
88 return UpdateCovenant(request);
89 case "update_estate":
90 return UpdateEstate(request);
91 case "estate_message":
92 return EstateMessage(request);
93 case "teleport_home_one_user":
94 return TeleportHomeOneUser(request);
95 case "teleport_home_all_users":
96 return TeleportHomeAllUsers(request);
97 }
98 }
99 finally
100 {
101 m_EstateModule.InInfoUpdate = false;
102 }
103 }
104 }
105 catch (Exception e)
106 {
107 m_log.Debug("[XESTATE]: Exception {0}" + e.ToString());
108 }
109
110 return FailureResult();
111 }
112
113 byte[] TeleportHomeAllUsers(Dictionary<string, object> request)
114 {
115 UUID PreyID = UUID.Zero;
116 int EstateID = 0;
117
118 if (!request.ContainsKey("EstateID"))
119 return FailureResult();
120
121 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
122 return FailureResult();
123
124 foreach (Scene s in m_EstateModule.Scenes)
125 {
126 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
127 {
128 s.ForEachScenePresence(delegate(ScenePresence p) {
129 if (p != null && !p.IsChildAgent)
130 {
131 p.ControllingClient.SendTeleportStart(16);
132 s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient);
133 }
134 });
135 }
136 }
137
138 return SuccessResult();
139 }
140
141 byte[] TeleportHomeOneUser(Dictionary<string, object> request)
142 {
143 UUID PreyID = UUID.Zero;
144 int EstateID = 0;
145
146 if (!request.ContainsKey("PreyID") ||
147 !request.ContainsKey("EstateID"))
148 {
149 return FailureResult();
150 }
151
152 if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID))
153 return FailureResult();
154
155 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
156 return FailureResult();
157
158 foreach (Scene s in m_EstateModule.Scenes)
159 {
160 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
161 {
162 ScenePresence p = s.GetScenePresence(PreyID);
163 if (p != null && !p.IsChildAgent)
164 {
165 p.ControllingClient.SendTeleportStart(16);
166 s.TeleportClientHome(PreyID, p.ControllingClient);
167 }
168 }
169 }
170
171 return SuccessResult();
172 }
173
174 byte[] EstateMessage(Dictionary<string, object> request)
175 {
176 UUID FromID = UUID.Zero;
177 string FromName = String.Empty;
178 string Message = String.Empty;
179 int EstateID = 0;
180
181 if (!request.ContainsKey("FromID") ||
182 !request.ContainsKey("FromName") ||
183 !request.ContainsKey("Message") ||
184 !request.ContainsKey("EstateID"))
185 {
186 return FailureResult();
187 }
188
189 if (!UUID.TryParse(request["FromID"].ToString(), out FromID))
190 return FailureResult();
191
192 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
193 return FailureResult();
194
195 FromName = request["FromName"].ToString();
196 Message = request["Message"].ToString();
197
198 foreach (Scene s in m_EstateModule.Scenes)
199 {
200 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
201 {
202 IDialogModule dm = s.RequestModuleInterface<IDialogModule>();
203
204 if (dm != null)
205 {
206 dm.SendNotificationToUsersInRegion(FromID, FromName,
207 Message);
208 }
209 }
210 }
211
212 return SuccessResult();
213 }
214
215 byte[] UpdateCovenant(Dictionary<string, object> request)
216 {
217 UUID CovenantID = UUID.Zero;
218 int EstateID = 0;
219
220 if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID"))
221 return FailureResult();
222
223 if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID))
224 return FailureResult();
225
226 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
227 return FailureResult();
228
229 foreach (Scene s in m_EstateModule.Scenes)
230 {
231 if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID)
232 s.RegionInfo.RegionSettings.Covenant = CovenantID;
233 }
234
235 return SuccessResult();
236 }
237
238 byte[] UpdateEstate(Dictionary<string, object> request)
239 {
240 int EstateID = 0;
241
242 if (!request.ContainsKey("EstateID"))
243 return FailureResult();
244 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
245 return FailureResult();
246
247 foreach (Scene s in m_EstateModule.Scenes)
248 {
249 if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID)
250 s.ReloadEstateData();
251 }
252 return SuccessResult();
253 }
254
255 private byte[] FailureResult()
256 {
257 return BoolResult(false);
258 }
259
260 private byte[] SuccessResult()
261 {
262 return BoolResult(true);
263 }
264
265 private byte[] BoolResult(bool value)
266 {
267 XmlDocument doc = new XmlDocument();
268
269 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
270 "", "");
271
272 doc.AppendChild(xmlnode);
273
274 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
275 "");
276
277 doc.AppendChild(rootElement);
278
279 XmlElement result = doc.CreateElement("", "RESULT", "");
280 result.AppendChild(doc.CreateTextNode(value.ToString()));
281
282 rootElement.AppendChild(result);
283
284 return Util.DocToBytes(doc);
285 }
286
287 }
288}
diff --git a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs
index bd22155..70c6028 100644
--- a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs
@@ -45,17 +45,19 @@ using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 45using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
46using OpenSim.Region.Framework.Interfaces; 46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes; 47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager; 48using OpenSim.Region.PhysicsModules.SharedBase;
49using OpenSim.Services.Interfaces; 49using OpenSim.Services.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 50using Caps = OpenSim.Framework.Capabilities.Caps;
51using GridRegion = OpenSim.Services.Interfaces.GridRegion; 51using GridRegion = OpenSim.Services.Interfaces.GridRegion;
52 52
53namespace OpenSim.Region.CoreModules.World.Land 53namespace OpenSim.Region.CoreModules.World.Land
54{ 54{
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DwellModule")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DefaultDwellModule")]
56 public class DwellModule : IDwellModule, INonSharedRegionModule 56 public class DefaultDwellModule : IDwellModule, INonSharedRegionModule
57 { 57 {
58 private Scene m_scene; 58 private Scene m_scene;
59 private IConfigSource m_Config;
60 private bool m_Enabled = false;
59 61
60 public Type ReplaceableInterface 62 public Type ReplaceableInterface
61 { 63 {
@@ -64,15 +66,27 @@ namespace OpenSim.Region.CoreModules.World.Land
64 66
65 public string Name 67 public string Name
66 { 68 {
67 get { return "DwellModule"; } 69 get { return "DefaultDwellModule"; }
68 } 70 }
69 71
70 public void Initialise(IConfigSource source) 72 public void Initialise(IConfigSource source)
71 { 73 {
74 m_Config = source;
75
76 IConfig DwellConfig = m_Config.Configs ["Dwell"];
77
78 if (DwellConfig == null) {
79 m_Enabled = false;
80 return;
81 }
82 m_Enabled = (DwellConfig.GetString ("DwellModule", "DefaultDwellModule") == "DefaultDwellModule");
72 } 83 }
73 84
74 public void AddRegion(Scene scene) 85 public void AddRegion(Scene scene)
75 { 86 {
87 if (!m_Enabled)
88 return;
89
76 m_scene = scene; 90 m_scene = scene;
77 91
78 m_scene.EventManager.OnNewClient += OnNewClient; 92 m_scene.EventManager.OnNewClient += OnNewClient;
diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
index 7fc358d..73c592d 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
@@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land
95 return null; 95 return null;
96 } 96 }
97 97
98 public ILandObject GetLandObject(Vector3 position)
99 {
100 return GetLandObject(position.X, position.Y);
101 }
102
98 public ILandObject GetLandObject(int x, int y) 103 public ILandObject GetLandObject(int x, int y)
99 { 104 {
100 if (m_landManagementModule != null) 105 if (m_landManagementModule != null)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index bad7205..92f6c1b 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -42,10 +42,9 @@ using OpenSim.Framework.Capabilities;
42using OpenSim.Framework.Console; 42using OpenSim.Framework.Console;
43using OpenSim.Framework.Servers; 43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
46using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes; 46using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager; 47using OpenSim.Region.PhysicsModules.SharedBase;
49using OpenSim.Services.Interfaces; 48using OpenSim.Services.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 49using Caps = OpenSim.Framework.Capabilities.Caps;
51using GridRegion = OpenSim.Services.Interfaces.GridRegion; 50using GridRegion = OpenSim.Services.Interfaces.GridRegion;
@@ -65,25 +64,27 @@ namespace OpenSim.Region.CoreModules.World.Land
65 public class LandManagementModule : INonSharedRegionModule 64 public class LandManagementModule : INonSharedRegionModule
66 { 65 {
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
68
69 /// <summary>
70 /// Minimum land unit size in region co-ordinates.
71 /// </summary>
72 public const int LandUnit = 4;
68 73
69 private static readonly string remoteParcelRequestPath = "0009/"; 74 private static readonly string remoteParcelRequestPath = "0009/";
70 75
71 private LandChannel landChannel; 76 private LandChannel landChannel;
72 private Scene m_scene; 77 private Scene m_scene;
73 protected Commander m_commander = new Commander("land"); 78
74 79 protected IGroupsModule m_groupManager;
75 protected IUserManagement m_userManager; 80 protected IUserManagement m_userManager;
76 protected IPrimCountModule m_primCountModule; 81 protected IPrimCountModule m_primCountModule;
77 82 protected IDialogModule m_Dialog;
78 // Minimum for parcels to work is 64m even if we don't actually use them.
79 #pragma warning disable 0429
80 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
81 #pragma warning restore 0429
82 83
83 /// <value> 84 /// <value>
84 /// Local land ids at specified region co-ordinates (region size / 4) 85 /// Local land ids at specified region co-ordinates (region size / 4)
85 /// </value> 86 /// </value>
86 private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; 87 private int[,] m_landIDList;
87 88
88 /// <value> 89 /// <value>
89 /// Land objects keyed by local id 90 /// Land objects keyed by local id
@@ -97,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land
97 // caches ExtendedLandData 98 // caches ExtendedLandData
98 private Cache parcelInfoCache; 99 private Cache parcelInfoCache;
99 100
101
100 /// <summary> 102 /// <summary>
101 /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. 103 /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
102 /// </summary> 104 /// </summary>
103 private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); 105 private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>();
104 106
107 // Enables limiting parcel layer info transmission when doing simple updates
108 private bool shouldLimitParcelLayerInfoToViewDistance { get; set; }
109 // "View distance" for sending parcel layer info if asked for from a view point in the region
110 private int parcelLayerViewDistance { get; set; }
111
105 #region INonSharedRegionModule Members 112 #region INonSharedRegionModule Members
106 113
107 public Type ReplaceableInterface 114 public Type ReplaceableInterface
@@ -111,12 +118,20 @@ namespace OpenSim.Region.CoreModules.World.Land
111 118
112 public void Initialise(IConfigSource source) 119 public void Initialise(IConfigSource source)
113 { 120 {
121 shouldLimitParcelLayerInfoToViewDistance = true;
122 parcelLayerViewDistance = 128;
123 IConfig landManagementConfig = source.Configs["LandManagement"];
124 if (landManagementConfig != null)
125 {
126 shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance);
127 parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance);
128 }
114 } 129 }
115 130
116 public void AddRegion(Scene scene) 131 public void AddRegion(Scene scene)
117 { 132 {
118 m_scene = scene; 133 m_scene = scene;
119 m_landIDList.Initialize(); 134 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
120 landChannel = new LandChannel(scene, this); 135 landChannel = new LandChannel(scene, this);
121 136
122 parcelInfoCache = new Cache(); 137 parcelInfoCache = new Cache();
@@ -139,28 +154,26 @@ namespace OpenSim.Region.CoreModules.World.Land
139 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; 154 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
140 m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan; 155 m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan;
141 m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps; 156 m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
142 m_scene.EventManager.OnPluginConsole += EventManagerOnPluginConsole;
143 157
144 lock (m_scene) 158 lock (m_scene)
145 { 159 {
146 m_scene.LandChannel = (ILandChannel)landChannel; 160 m_scene.LandChannel = (ILandChannel)landChannel;
147 } 161 }
148 162
149 InstallInterfaces(); 163 RegisterCommands();
150 } 164 }
151 165
152 public void RegionLoaded(Scene scene) 166 public void RegionLoaded(Scene scene)
153 { 167 {
154 m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); 168 m_userManager = m_scene.RequestModuleInterface<IUserManagement>();
155 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); 169 m_groupManager = m_scene.RequestModuleInterface<IGroupsModule>();
170 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>();
171 m_Dialog = m_scene.RequestModuleInterface<IDialogModule>();
156 } 172 }
157 173
158 public void RemoveRegion(Scene scene) 174 public void RemoveRegion(Scene scene)
159 { 175 {
160 // TODO: Also release other event manager listeners here 176 // TODO: Release event manager listeners here
161
162 m_scene.EventManager.OnPluginConsole -= EventManagerOnPluginConsole;
163 m_scene.UnregisterModuleCommander(m_commander.Name);
164 } 177 }
165 178
166// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason) 179// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
@@ -168,30 +181,7 @@ namespace OpenSim.Region.CoreModules.World.Land
168// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y); 181// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
169// reason = "You are not allowed to enter this sim."; 182// reason = "You are not allowed to enter this sim.";
170// return nearestParcel != null; 183// return nearestParcel != null;
171// } 184// }
172
173 /// <summary>
174 /// Processes commandline input. Do not call directly.
175 /// </summary>
176 /// <param name="args">Commandline arguments</param>
177 protected void EventManagerOnPluginConsole(string[] args)
178 {
179 if (args[0] == "land")
180 {
181 if (args.Length == 1)
182 {
183 m_commander.ProcessConsoleCommand("help", new string[0]);
184 return;
185 }
186
187 string[] tmpArgs = new string[args.Length - 2];
188 int i;
189 for (i = 2; i < args.Length; i++)
190 tmpArgs[i - 2] = args[i];
191
192 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
193 }
194 }
195 185
196 void EventManagerOnNewClient(IClientAPI client) 186 void EventManagerOnNewClient(IClientAPI client)
197 { 187 {
@@ -210,6 +200,10 @@ namespace OpenSim.Region.CoreModules.World.Land
210 client.OnParcelInfoRequest += ClientOnParcelInfoRequest; 200 client.OnParcelInfoRequest += ClientOnParcelInfoRequest;
211 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; 201 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup;
212 client.OnPreAgentUpdate += ClientOnPreAgentUpdate; 202 client.OnPreAgentUpdate += ClientOnPreAgentUpdate;
203 client.OnParcelEjectUser += ClientOnParcelEjectUser;
204 client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
205 client.OnSetStartLocationRequest += ClientOnSetHome;
206
213 207
214 EntityBase presenceEntity; 208 EntityBase presenceEntity;
215 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) 209 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence)
@@ -293,14 +287,15 @@ namespace OpenSim.Region.CoreModules.World.Land
293 LandData newData = data.Copy(); 287 LandData newData = data.Copy();
294 newData.LocalID = local_id; 288 newData.LocalID = local_id;
295 289
290 ILandObject land;
296 lock (m_landList) 291 lock (m_landList)
297 { 292 {
298 if (m_landList.ContainsKey(local_id)) 293 if (m_landList.TryGetValue(local_id, out land))
299 { 294 land.LandData = newData;
300 m_landList[local_id].LandData = newData;
301 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, m_landList[local_id]);
302 }
303 } 295 }
296
297 if (land != null)
298 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land);
304 } 299 }
305 300
306 public bool AllowedForcefulBans 301 public bool AllowedForcefulBans
@@ -319,7 +314,7 @@ namespace OpenSim.Region.CoreModules.World.Land
319 { 314 {
320 m_landList.Clear(); 315 m_landList.Clear();
321 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 316 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
322 m_landIDList.Initialize(); 317 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
323 } 318 }
324 } 319 }
325 320
@@ -333,7 +328,8 @@ namespace OpenSim.Region.CoreModules.World.Land
333 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); 328 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
334 329
335 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); 330 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
336 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); 331 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0,
332 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY));
337 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 333 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
338 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); 334 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
339 335
@@ -460,8 +456,8 @@ namespace OpenSim.Region.CoreModules.World.Land
460 456
461 public void SendLandUpdate(ScenePresence avatar, bool force) 457 public void SendLandUpdate(ScenePresence avatar, bool force)
462 { 458 {
463 ILandObject over = GetLandObject((int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), 459 ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
464 (int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); 460 (int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
465 461
466 if (over != null) 462 if (over != null)
467 { 463 {
@@ -543,16 +539,13 @@ namespace OpenSim.Region.CoreModules.World.Land
543 /// </summary> 539 /// </summary>
544 /// <param name="avatar"></param> 540 /// <param name="avatar"></param>
545 public void EventManagerOnClientMovement(ScenePresence avatar) 541 public void EventManagerOnClientMovement(ScenePresence avatar)
546 //
547 { 542 {
548 ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 543 Vector3 pos = avatar.AbsolutePosition;
544 ILandObject over = GetLandObject(pos.X, pos.Y);
549 if (over != null) 545 if (over != null)
550 { 546 {
551 if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT)) 547 if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || pos.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT))
552 { 548 avatar.lastKnownAllowedPosition = pos;
553 avatar.lastKnownAllowedPosition =
554 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
555 }
556 } 549 }
557 } 550 }
558 551
@@ -611,7 +604,10 @@ namespace OpenSim.Region.CoreModules.World.Land
611 /// <summary> 604 /// <summary>
612 /// Adds a land object to the stored list and adds them to the landIDList to what they own 605 /// Adds a land object to the stored list and adds them to the landIDList to what they own
613 /// </summary> 606 /// </summary>
614 /// <param name="new_land">The land object being added</param> 607 /// <param name="new_land">
608 /// The land object being added.
609 /// Will return null if this overlaps with an existing parcel that has not had its bitmap adjusted.
610 /// </param>
615 public ILandObject AddLandObject(ILandObject land) 611 public ILandObject AddLandObject(ILandObject land)
616 { 612 {
617 ILandObject new_land = land.Copy(); 613 ILandObject new_land = land.Copy();
@@ -619,34 +615,76 @@ namespace OpenSim.Region.CoreModules.World.Land
619 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated 615 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated
620 // as a random UUID inside LandData initialization 616 // as a random UUID inside LandData initialization
621 if (m_primCountModule != null) 617 if (m_primCountModule != null)
622 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); 618 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID);
623 619
624 lock (m_landList) 620 lock (m_landList)
625 { 621 {
626 int newLandLocalID = ++m_lastLandLocalID; 622 int newLandLocalID = m_lastLandLocalID + 1;
627 new_land.LandData.LocalID = newLandLocalID; 623 new_land.LandData.LocalID = newLandLocalID;
628 624
629 bool[,] landBitmap = new_land.GetLandBitmap(); 625 bool[,] landBitmap = new_land.GetLandBitmap();
630 for (int x = 0; x < landArrayMax; x++) 626 // m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). newLocalID={3}",
627 // LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), newLandLocalID);
628
629 if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1))
630 {
631 // Going to variable sized regions can cause mismatches
632 m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})",
633 LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1) );
634 }
635 else
631 { 636 {
632 for (int y = 0; y < landArrayMax; y++) 637 // If other land objects still believe that they occupy any parts of the same space,
638 // then do not allow the add to proceed.
639 for (int x = 0; x < landBitmap.GetLength(0); x++)
633 { 640 {
634 if (landBitmap[x, y]) 641 for (int y = 0; y < landBitmap.GetLength(1); y++)
635 { 642 {
636// m_log.DebugFormat( 643 if (landBitmap[x, y])
637// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", 644 {
638// new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); 645 int lastRecordedLandId = m_landIDList[x, y];
639 646
640 m_landIDList[x, y] = newLandLocalID; 647 if (lastRecordedLandId > 0)
648 {
649 ILandObject lastRecordedLo = m_landList[lastRecordedLandId];
650
651 if (lastRecordedLo.LandBitmap[x, y])
652 {
653 m_log.ErrorFormat(
654 "{0}: Cannot add parcel \"{1}\", local ID {2} at tile {3},{4} because this is still occupied by parcel \"{5}\", local ID {6} in {7}",
655 LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y,
656 lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name);
657
658 return null;
659 }
660 }
661 }
662 }
663 }
664
665 for (int x = 0; x < landBitmap.GetLength(0); x++)
666 {
667 for (int y = 0; y < landBitmap.GetLength(1); y++)
668 {
669 if (landBitmap[x, y])
670 {
671 // m_log.DebugFormat(
672 // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
673 // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
674
675 m_landIDList[x, y] = newLandLocalID;
676 }
641 } 677 }
642 } 678 }
643 } 679 }
644 680
645 m_landList.Add(newLandLocalID, new_land); 681 m_landList.Add(newLandLocalID, new_land);
682 m_lastLandLocalID++;
646 } 683 }
647 684
648 new_land.ForceUpdateLandInfo(); 685 new_land.ForceUpdateLandInfo();
649 m_scene.EventManager.TriggerLandObjectAdded(new_land); 686 m_scene.EventManager.TriggerLandObjectAdded(new_land);
687
650 return new_land; 688 return new_land;
651 } 689 }
652 690
@@ -656,11 +694,12 @@ namespace OpenSim.Region.CoreModules.World.Land
656 /// <param name="local_id">Land.localID of the peice of land to remove.</param> 694 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
657 public void removeLandObject(int local_id) 695 public void removeLandObject(int local_id)
658 { 696 {
697 ILandObject land;
659 lock (m_landList) 698 lock (m_landList)
660 { 699 {
661 for (int x = 0; x < 64; x++) 700 for (int x = 0; x < m_landIDList.GetLength(0); x++)
662 { 701 {
663 for (int y = 0; y < 64; y++) 702 for (int y = 0; y < m_landIDList.GetLength(1); y++)
664 { 703 {
665 if (m_landIDList[x, y] == local_id) 704 if (m_landIDList[x, y] == local_id)
666 { 705 {
@@ -672,9 +711,11 @@ namespace OpenSim.Region.CoreModules.World.Land
672 } 711 }
673 } 712 }
674 713
675 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[local_id].LandData.GlobalID); 714 land = m_landList[local_id];
676 m_landList.Remove(local_id); 715 m_landList.Remove(local_id);
677 } 716 }
717
718 m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID);
678 } 719 }
679 720
680 /// <summary> 721 /// <summary>
@@ -682,21 +723,27 @@ namespace OpenSim.Region.CoreModules.World.Land
682 /// </summary> 723 /// </summary>
683 public void Clear(bool setupDefaultParcel) 724 public void Clear(bool setupDefaultParcel)
684 { 725 {
726 List<ILandObject> parcels;
685 lock (m_landList) 727 lock (m_landList)
686 { 728 {
687 foreach (ILandObject lo in m_landList.Values) 729 parcels = new List<ILandObject>(m_landList.Values);
688 { 730 }
689 //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID); 731
690 m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID); 732 foreach (ILandObject lo in parcels)
691 } 733 {
734 //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID);
735 m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID);
736 }
692 737
738 lock (m_landList)
739 {
693 m_landList.Clear(); 740 m_landList.Clear();
694 741
695 ResetSimLandObjects(); 742 ResetSimLandObjects();
696
697 if (setupDefaultParcel)
698 CreateDefaultParcel();
699 } 743 }
744
745 if (setupDefaultParcel)
746 CreateDefaultParcel();
700 } 747 }
701 748
702 private void performFinalLandJoin(ILandObject master, ILandObject slave) 749 private void performFinalLandJoin(ILandObject master, ILandObject slave)
@@ -704,9 +751,9 @@ namespace OpenSim.Region.CoreModules.World.Land
704 bool[,] landBitmapSlave = slave.GetLandBitmap(); 751 bool[,] landBitmapSlave = slave.GetLandBitmap();
705 lock (m_landList) 752 lock (m_landList)
706 { 753 {
707 for (int x = 0; x < 64; x++) 754 for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
708 { 755 {
709 for (int y = 0; y < 64; y++) 756 for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
710 { 757 {
711 if (landBitmapSlave[x, y]) 758 if (landBitmapSlave[x, y])
712 { 759 {
@@ -740,23 +787,28 @@ namespace OpenSim.Region.CoreModules.World.Land
740 /// <returns>Land object at the point supplied</returns> 787 /// <returns>Land object at the point supplied</returns>
741 public ILandObject GetLandObject(float x_float, float y_float) 788 public ILandObject GetLandObject(float x_float, float y_float)
742 { 789 {
790 return GetLandObject((int)x_float, (int)y_float, true /* returnNullIfLandObjectNotFound */);
791 /*
743 int x; 792 int x;
744 int y; 793 int y;
745 794
746 if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) 795 if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0)
747 return null; 796 return null;
748 797
749 try 798 try
750 { 799 {
751 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); 800 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit));
752 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); 801 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit));
753 } 802 }
754 catch (OverflowException) 803 catch (OverflowException)
755 { 804 {
756 return null; 805 return null;
757 } 806 }
758 807
759 if (x >= 64 || y >= 64 || x < 0 || y < 0) 808 if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit)
809 || y >= (m_scene.RegionInfo.RegionSizeY / landUnit)
810 || x < 0
811 || y < 0)
760 { 812 {
761 return null; 813 return null;
762 } 814 }
@@ -772,38 +824,70 @@ namespace OpenSim.Region.CoreModules.World.Land
772// m_log.DebugFormat( 824// m_log.DebugFormat(
773// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", 825// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}",
774// x, y, m_scene.RegionInfo.RegionName); 826// x, y, m_scene.RegionInfo.RegionName);
775 827
776 if (m_landList.ContainsKey(m_landIDList[x, y])) 828 try
777 return m_landList[m_landIDList[x, y]]; 829 {
830 if (m_landList.ContainsKey(m_landIDList[x, y]))
831 return m_landList[m_landIDList[x, y]];
832 }
833 catch (Exception e)
834 {
835 m_log.DebugFormat("{0} GetLandObject exception. x={1}, y={2}, m_landIDList.len=({3},{4})",
836 LogHeader, x, y, m_landIDList.GetLength(0), m_landIDList.GetLength(1));
837 }
778 838
779 return null; 839 return null;
780 } 840 }
841 */
781 } 842 }
782 843
844 // Public entry.
845 // Throws exception if land object is not found
783 public ILandObject GetLandObject(int x, int y) 846 public ILandObject GetLandObject(int x, int y)
784 { 847 {
785 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) 848 return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */);
849 }
850
851 /// <summary>
852 /// Given a region position, return the parcel land object for that location
853 /// </summary>
854 /// <returns>
855 /// The land object.
856 /// </returns>
857 /// <param name='x'></param>
858 /// <param name='y'></param>
859 /// <param name='returnNullIfLandObjectNotFound'>
860 /// Return null if the land object requested is not within the region's bounds.
861 /// </param>
862 private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds)
863 {
864 if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0)
786 { 865 {
787 // These exceptions here will cause a lot of complaints from the users specifically because 866 // These exceptions here will cause a lot of complaints from the users specifically because
788 // they happen every time at border crossings 867 // they happen every time at border crossings
789 throw new Exception("Error: Parcel not found at point " + x + ", " + y); 868 if (returnNullIfLandObjectOutsideBounds)
790 }
791
792 lock (m_landIDList)
793 {
794 try
795 {
796 return m_landList[m_landIDList[x / 4, y / 4]];
797 }
798 catch (IndexOutOfRangeException)
799 {
800// m_log.WarnFormat(
801// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
802// x, y, m_scene.RegionInfo.RegionName);
803
804 return null; 869 return null;
805 } 870 else
871 throw new Exception(
872 String.Format("{0} GetLandObject for non-existent position. Region={1}, pos=<{2},{3}",
873 LogHeader, m_scene.RegionInfo.RegionName, x, y)
874 );
806 } 875 }
876
877 return m_landList[m_landIDList[x / 4, y / 4]];
878 }
879
880 // Create a 'parcel is here' bitmap for the parcel identified by the passed landID
881 private bool[,] CreateBitmapForID(int landID)
882 {
883 bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)];
884
885 for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
886 for (int yy = 0; yy < m_landIDList.GetLength(0); yy++)
887 if (m_landIDList[xx, yy] == landID)
888 ret[xx, yy] = true;
889
890 return ret;
807 } 891 }
808 892
809 #endregion 893 #endregion
@@ -973,8 +1057,12 @@ namespace OpenSim.Region.CoreModules.World.Land
973 1057
974 //Now add the new land object 1058 //Now add the new land object
975 ILandObject result = AddLandObject(newLand); 1059 ILandObject result = AddLandObject(newLand);
976 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); 1060
977 result.SendLandUpdateToAvatarsOverMe(); 1061 if (result != null)
1062 {
1063 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData);
1064 result.SendLandUpdateToAvatarsOverMe();
1065 }
978 } 1066 }
979 1067
980 /// <summary> 1068 /// <summary>
@@ -1055,96 +1143,164 @@ namespace OpenSim.Region.CoreModules.World.Land
1055 1143
1056 #region Parcel Updating 1144 #region Parcel Updating
1057 1145
1146 // Send parcel layer info for the whole region
1147 public void SendParcelOverlay(IClientAPI remote_client)
1148 {
1149 SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize);
1150 }
1151
1058 /// <summary> 1152 /// <summary>
1059 /// Where we send the ParcelOverlay packet to the client 1153 /// Send the parcel overlay blocks to the client. We send the overlay packets
1154 /// around a location and limited by the 'parcelLayerViewDistance'. This number
1155 /// is usually 128 and the code is arranged so it sends all the parcel overlay
1156 /// information for a whole region if the region is legacy sized (256x256). If
1157 /// the region is larger, only the parcel layer information is sent around
1158 /// the point specified. This reduces the problem of parcel layer information
1159 /// blocks increasing exponentially as region size increases.
1060 /// </summary> 1160 /// </summary>
1061 /// <param name="remote_client">The object representing the client</param> 1161 /// <param name="remote_client">The object representing the client</param>
1062 public void SendParcelOverlay(IClientAPI remote_client) 1162 /// <param name="xPlace">X position in the region to send surrounding parcel layer info</param>
1163 /// <param name="yPlace">y position in the region to send surrounding parcel layer info</param>
1164 /// <param name="layerViewDistance">Distance from x,y position to send parcel layer info</param>
1165 private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance)
1063 { 1166 {
1064 const int LAND_BLOCKS_PER_PACKET = 1024; 1167 const int LAND_BLOCKS_PER_PACKET = 1024;
1065 1168
1066 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 1169 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1067 int byteArrayCount = 0; 1170 int byteArrayCount = 0;
1068 int sequenceID = 0; 1171 int sequenceID = 0;
1069 int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize;
1070 1172
1173 int xLow = 0;
1174 int xHigh = (int)m_scene.RegionInfo.RegionSizeX;
1175 int yLow = 0;
1176 int yHigh = (int)m_scene.RegionInfo.RegionSizeY;
1071 1177
1072 for (int y = 0; y < blockmeters; y++) 1178 if (shouldLimitParcelLayerInfoToViewDistance)
1073 { 1179 {
1074 for (int x = 0; x < blockmeters; x++) 1180 // Compute view distance around the given point
1181 int txLow = xPlace - layerViewDistance;
1182 int txHigh = xPlace + layerViewDistance;
1183 // If the distance is outside the region area, move the view distance to ba all in the region
1184 if (txLow < xLow)
1185 {
1186 txLow = xLow;
1187 txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh);
1188 }
1189 if (txHigh > xHigh)
1075 { 1190 {
1076 byte tempByte = 0; //This represents the byte for the current 4x4 1191 txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2));
1192 txHigh = xHigh;
1193 }
1194 xLow = txLow;
1195 xHigh = txHigh;
1077 1196
1078 ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4); 1197 int tyLow = yPlace - layerViewDistance;
1198 int tyHigh = yPlace + layerViewDistance;
1199 if (tyLow < yLow)
1200 {
1201 tyLow = yLow;
1202 tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh);
1203 }
1204 if (tyHigh > yHigh)
1205 {
1206 tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2));
1207 tyHigh = yHigh;
1208 }
1209 yLow = tyLow;
1210 yHigh = tyHigh;
1211 }
1212 // m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>",
1213 // LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh);
1079 1214
1080 if (currentParcelBlock != null) 1215 // Layer data is in landUnit (4m) chunks
1216 for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1217 {
1218 for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1219 {
1220 byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client);
1221 byteArrayCount++;
1222 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
1081 { 1223 {
1082 if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) 1224 // m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length);
1083 { 1225 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1084 //Owner Flag 1226 byteArrayCount = 0;
1085 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); 1227 sequenceID++;
1086 } 1228 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1087 else if (currentParcelBlock.LandData.SalePrice > 0 && 1229 }
1088 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1089 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1090 {
1091 //Sale Flag
1092 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
1093 }
1094 else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1095 {
1096 //Public Flag
1097 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
1098 }
1099 else
1100 {
1101 //Other Flag
1102 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
1103 }
1104 1230
1105 //Now for border control 1231 }
1232 }
1106 1233
1107 ILandObject westParcel = null; 1234 if (byteArrayCount != 0)
1108 ILandObject southParcel = null; 1235 {
1109 if (x > 0) 1236 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1110 { 1237 // m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length);
1111 westParcel = GetLandObject((x - 1) * 4, y * 4); 1238 }
1112 } 1239 }
1113 if (y > 0)
1114 {
1115 southParcel = GetLandObject(x * 4, (y - 1) * 4);
1116 }
1117 1240
1118 if (x == 0) 1241 private byte BuildLayerByte(ILandObject currentParcelBlock, int x, int y, IClientAPI remote_client)
1119 { 1242 {
1120 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); 1243 byte tempByte = 0; //This represents the byte for the current 4x4
1121 }
1122 else if (westParcel != null && westParcel != currentParcelBlock)
1123 {
1124 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1125 }
1126 1244
1127 if (y == 0) 1245 if (currentParcelBlock != null)
1128 { 1246 {
1129 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); 1247 if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId)
1130 } 1248 {
1131 else if (southParcel != null && southParcel != currentParcelBlock) 1249 //Owner Flag
1132 { 1250 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
1133 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); 1251 }
1134 } 1252 else if (currentParcelBlock.LandData.SalePrice > 0 &&
1253 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1254 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1255 {
1256 //Sale Flag
1257 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
1258 }
1259 else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1260 {
1261 //Public Flag
1262 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
1263 }
1264 else
1265 {
1266 //Other Flag
1267 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
1268 }
1135 1269
1136 byteArray[byteArrayCount] = tempByte; 1270 //Now for border control
1137 byteArrayCount++; 1271
1138 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) 1272 ILandObject westParcel = null;
1139 { 1273 ILandObject southParcel = null;
1140 remote_client.SendLandParcelOverlay(byteArray, sequenceID); 1274 if (x > 0)
1141 byteArrayCount = 0; 1275 {
1142 sequenceID++; 1276 westParcel = GetLandObject((x - 1) * LandUnit, y * LandUnit);
1143 byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 1277 }
1144 } 1278 if (y > 0)
1145 } 1279 {
1280 southParcel = GetLandObject(x * LandUnit, (y - 1) * LandUnit);
1281 }
1282
1283 if (x == 0)
1284 {
1285 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1286 }
1287 else if (westParcel != null && westParcel != currentParcelBlock)
1288 {
1289 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1146 } 1290 }
1291
1292 if (y == 0)
1293 {
1294 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1295 }
1296 else if (southParcel != null && southParcel != currentParcelBlock)
1297 {
1298 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1299 }
1300
1147 } 1301 }
1302
1303 return tempByte;
1148 } 1304 }
1149 1305
1150 public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, 1306 public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
@@ -1182,7 +1338,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1182 temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); 1338 temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
1183 } 1339 }
1184 1340
1185 SendParcelOverlay(remote_client); 1341 // Also send the layer data around the point of interest
1342 SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance);
1186 } 1343 }
1187 1344
1188 public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) 1345 public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
@@ -1254,6 +1411,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1254 1411
1255 m_scene.ForEachClient(SendParcelOverlay); 1412 m_scene.ForEachClient(SendParcelOverlay);
1256 land.SendLandUpdateToClient(true, remote_client); 1413 land.SendLandUpdateToClient(true, remote_client);
1414 UpdateLandObject(land.LandData.LocalID, land.LandData);
1257 } 1415 }
1258 } 1416 }
1259 } 1417 }
@@ -1274,8 +1432,10 @@ namespace OpenSim.Region.CoreModules.World.Land
1274 land.LandData.GroupID = UUID.Zero; 1432 land.LandData.GroupID = UUID.Zero;
1275 land.LandData.IsGroupOwned = false; 1433 land.LandData.IsGroupOwned = false;
1276 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); 1434 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1435
1277 m_scene.ForEachClient(SendParcelOverlay); 1436 m_scene.ForEachClient(SendParcelOverlay);
1278 land.SendLandUpdateToClient(true, remote_client); 1437 land.SendLandUpdateToClient(true, remote_client);
1438 UpdateLandObject(land.LandData.LocalID, land.LandData);
1279 } 1439 }
1280 } 1440 }
1281 } 1441 }
@@ -1302,6 +1462,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1302 1462
1303 m_scene.ForEachClient(SendParcelOverlay); 1463 m_scene.ForEachClient(SendParcelOverlay);
1304 land.SendLandUpdateToClient(true, remote_client); 1464 land.SendLandUpdateToClient(true, remote_client);
1465 UpdateLandObject(land.LandData.LocalID, land.LandData);
1305 } 1466 }
1306 } 1467 }
1307 } 1468 }
@@ -1382,19 +1543,78 @@ namespace OpenSim.Region.CoreModules.World.Land
1382 1543
1383 #region Land Object From Storage Functions 1544 #region Land Object From Storage Functions
1384 1545
1385 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) 1546 private void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1386 { 1547 {
1387// m_log.DebugFormat( 1548// m_log.DebugFormat(
1388// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name); 1549// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name);
1389 1550
1390 for (int i = 0; i < data.Count; i++) 1551 // Prevent race conditions from any auto-creation of new parcels for varregions whilst we are still loading
1391 IncomingLandObjectFromStorage(data[i]); 1552 // the existing parcels.
1553 lock (m_landList)
1554 {
1555 for (int i = 0; i < data.Count; i++)
1556 IncomingLandObjectFromStorage(data[i]);
1557
1558 // Layer data is in landUnit (4m) chunks
1559 for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1560 {
1561 for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1562 {
1563 if (m_landIDList[x, y] == 0)
1564 {
1565 if (m_landList.Count == 1)
1566 {
1567 m_log.DebugFormat(
1568 "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}",
1569 LogHeader, x, y, m_scene.Name);
1570
1571 int onlyParcelID = 0;
1572 ILandObject onlyLandObject = null;
1573 foreach (KeyValuePair<int, ILandObject> kvp in m_landList)
1574 {
1575 onlyParcelID = kvp.Key;
1576 onlyLandObject = kvp.Value;
1577 break;
1578 }
1579
1580 // There is only one parcel. Grow it to fill all the unallocated spaces.
1581 for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
1582 for (int yy = 0; yy < m_landIDList.GetLength(1); yy++)
1583 if (m_landIDList[xx, yy] == 0)
1584 m_landIDList[xx, yy] = onlyParcelID;
1585
1586 onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID);
1587 }
1588 else if (m_landList.Count > 1)
1589 {
1590 m_log.DebugFormat(
1591 "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}",
1592 LogHeader, x, y, m_scene.Name);
1593
1594 // There are several other parcels so we must create a new one for the unassigned space
1595 ILandObject newLand = new LandObject(UUID.Zero, false, m_scene);
1596 // Claim all the unclaimed "0" ids
1597 newLand.SetLandBitmap(CreateBitmapForID(0));
1598 newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1599 newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
1600 newLand = AddLandObject(newLand);
1601 }
1602 else
1603 {
1604 // We should never reach this point as the separate code path when no land data exists should have fired instead.
1605 m_log.WarnFormat(
1606 "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present",
1607 LogHeader, m_scene.Name);
1608 }
1609 }
1610 }
1611 }
1612 }
1392 } 1613 }
1393 1614
1394 public void IncomingLandObjectFromStorage(LandData data) 1615 private void IncomingLandObjectFromStorage(LandData data)
1395 { 1616 {
1396 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); 1617 ILandObject new_land = new LandObject(data, m_scene);
1397 new_land.LandData = data.Copy();
1398 new_land.SetLandBitmapFromByteArray(); 1618 new_land.SetLandBitmapFromByteArray();
1399 AddLandObject(new_land); 1619 AddLandObject(new_land);
1400 } 1620 }
@@ -1409,7 +1629,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1409 m_landList.TryGetValue(localID, out selectedParcel); 1629 m_landList.TryGetValue(localID, out selectedParcel);
1410 } 1630 }
1411 1631
1412 if (selectedParcel == null) return; 1632 if (selectedParcel == null)
1633 return;
1413 1634
1414 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); 1635 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
1415 } 1636 }
@@ -1417,7 +1638,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1417 { 1638 {
1418 if (returnType != 1) 1639 if (returnType != 1)
1419 { 1640 {
1420 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown return type {0}", returnType); 1641 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType);
1421 return; 1642 return;
1422 } 1643 }
1423 1644
@@ -1437,14 +1658,14 @@ namespace OpenSim.Region.CoreModules.World.Land
1437 } 1658 }
1438 else 1659 else
1439 { 1660 {
1440 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown object {0}", groupID); 1661 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID);
1441 } 1662 }
1442 } 1663 }
1443 1664
1444 int num = 0; 1665 int num = 0;
1445 foreach (HashSet<SceneObjectGroup> objs in returns.Values) 1666 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1446 num += objs.Count; 1667 num += objs.Count;
1447 m_log.DebugFormat("[LAND MANAGEMENT MODULE] Returning {0} specific object(s)", num); 1668 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num);
1448 1669
1449 foreach (HashSet<SceneObjectGroup> objs in returns.Values) 1670 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1450 { 1671 {
@@ -1455,7 +1676,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1455 } 1676 }
1456 else 1677 else
1457 { 1678 {
1458 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}", 1679 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
1459 objs2.Count, objs2[0].OwnerID); 1680 objs2.Count, objs2[0].OwnerID);
1460 } 1681 }
1461 } 1682 }
@@ -1464,11 +1685,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1464 1685
1465 public void EventManagerOnNoLandDataFromStorage() 1686 public void EventManagerOnNoLandDataFromStorage()
1466 { 1687 {
1467 lock (m_landList) 1688 ResetSimLandObjects();
1468 { 1689 CreateDefaultParcel();
1469 ResetSimLandObjects();
1470 CreateDefaultParcel();
1471 }
1472 } 1690 }
1473 1691
1474 #endregion 1692 #endregion
@@ -1694,7 +1912,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1694 { 1912 {
1695 // most likely still cached from building the extLandData entry 1913 // most likely still cached from building the extLandData entry
1696 uint x = 0, y = 0; 1914 uint x = 0, y = 0;
1697 Utils.LongToUInts(data.RegionHandle, out x, out y); 1915 Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y);
1698 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); 1916 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
1699 } 1917 }
1700 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. 1918 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
@@ -1730,66 +1948,332 @@ namespace OpenSim.Region.CoreModules.World.Land
1730 UpdateLandObject(localID, land.LandData); 1948 UpdateLandObject(localID, land.LandData);
1731 } 1949 }
1732 1950
1733 protected void InstallInterfaces() 1951 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1952
1953 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1954 {
1955 ScenePresence targetAvatar = null;
1956 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1957 ScenePresence parcelManager = null;
1958 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1959 System.Threading.Timer Timer;
1960
1961 if (targetAvatar.UserLevel == 0)
1962 {
1963 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1964 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1965 return;
1966 if (flags == 0)
1967 {
1968 targetAvatar.AllowMovement = false;
1969 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1970 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1971 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1972 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1973 Timers.Add(targetAvatar.UUID, Timer);
1974 }
1975 else
1976 {
1977 targetAvatar.AllowMovement = true;
1978 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1979 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1980 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1981 Timers.Remove(targetAvatar.UUID);
1982 Timer.Dispose();
1983 }
1984 }
1985 }
1986
1987 private void OnEndParcelFrozen(object avatar)
1734 { 1988 {
1735 Command clearCommand 1989 ScenePresence targetAvatar = (ScenePresence)avatar;
1736 = new Command("clear", CommandIntentions.COMMAND_HAZARDOUS, ClearCommand, "Clears all the parcels from the region."); 1990 targetAvatar.AllowMovement = true;
1737 Command showCommand 1991 System.Threading.Timer Timer;
1738 = new Command("show", CommandIntentions.COMMAND_STATISTICAL, ShowParcelsCommand, "Shows all parcels on the region."); 1992 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1993 Timers.Remove(targetAvatar.UUID);
1994 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1995 }
1996
1997 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1998 {
1999 ScenePresence targetAvatar = null;
2000 ScenePresence parcelManager = null;
2001
2002 // Must have presences
2003 if (!m_scene.TryGetScenePresence(target, out targetAvatar) ||
2004 !m_scene.TryGetScenePresence(client.AgentId, out parcelManager))
2005 return;
2006
2007 // Cannot eject estate managers or gods
2008 if (m_scene.Permissions.IsAdministrator(target))
2009 return;
2010
2011 // Check if you even have permission to do this
2012 ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
2013 if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) &&
2014 !m_scene.Permissions.IsAdministrator(client.AgentId))
2015 return;
2016 Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land);
2017
2018 targetAvatar.TeleportWithMomentum(pos, null);
2019 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
2020 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1739 2021
1740 m_commander.RegisterCommand("clear", clearCommand); 2022 if ((flags & 1) != 0) // Ban TODO: Remove magic number
1741 m_commander.RegisterCommand("show", showCommand); 2023 {
2024 LandAccessEntry entry = new LandAccessEntry();
2025 entry.AgentID = targetAvatar.UUID;
2026 entry.Flags = AccessList.Ban;
2027 entry.Expires = 0; // Perm
1742 2028
1743 // Add this to our scene so scripts can call these functions 2029 land.LandData.ParcelAccessList.Add(entry);
1744 m_scene.RegisterModuleCommander(m_commander); 2030 }
2031 }
2032
2033 /// <summary>
2034 /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
2035 /// </summary>
2036 /// <param name="remoteClient"></param>
2037 /// <param name="regionHandle"></param>
2038 /// <param name="position"></param>
2039 /// <param name="lookAt"></param>
2040 /// <param name="flags"></param>
2041 public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2042 {
2043 // Let's find the parcel in question
2044 ILandObject land = landChannel.GetLandObject(position);
2045 if (land == null || m_scene.GridUserService == null)
2046 {
2047 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2048 return;
2049 }
2050
2051 // Gather some data
2052 ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID);
2053 SceneObjectGroup telehub = null;
2054 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
2055 // Does the telehub exist in the scene?
2056 telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
2057
2058 // Can the user set home here?
2059 if (// Required: local user; foreign users cannot set home
2060 m_scene.UserManagementModule.IsLocalGridUser(remoteClient.AgentId) &&
2061 (// (a) gods and land managers can set home
2062 m_scene.Permissions.IsAdministrator(remoteClient.AgentId) ||
2063 m_scene.Permissions.IsGod(remoteClient.AgentId) ||
2064 // (b) land owners can set home
2065 remoteClient.AgentId == land.LandData.OwnerID ||
2066 // (c) members of the land-associated group in roles that can set home
2067 ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) ||
2068 // (d) parcels with telehubs can be the home of anyone
2069 (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))))
2070 {
2071 string userId;
2072 UUID test;
2073 if (!m_scene.UserManagementModule.GetUserUUI(remoteClient.AgentId, out userId))
2074 {
2075 /* Do not set a home position in this grid for a HG visitor */
2076 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (User Lookup)");
2077 }
2078 else if (!UUID.TryParse(userId, out test))
2079 {
2080 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (HG visitor)");
2081 }
2082 else if (m_scene.GridUserService.SetHome(userId, land.RegionUUID, position, lookAt))
2083 {
2084 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2085 m_Dialog.SendAlertToUser(remoteClient, "Home position set.");
2086 }
2087 else
2088 {
2089 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2090 }
2091 }
2092 else
2093 m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel.");
2094 }
2095
2096 protected void RegisterCommands()
2097 {
2098 ICommands commands = MainConsole.Instance.Commands;
2099
2100 commands.AddCommand(
2101 "Land", false, "land clear",
2102 "land clear",
2103 "Clear all the parcels from the region.",
2104 "Command will ask for confirmation before proceeding.",
2105 HandleClearCommand);
2106
2107 commands.AddCommand(
2108 "Land", false, "land show",
2109 "land show [<local-land-id>]",
2110 "Show information about the parcels on the region.",
2111 "If no local land ID is given, then summary information about all the parcels is shown.\n"
2112 + "If a local land ID is given then full information about that parcel is shown.",
2113 HandleShowCommand);
1745 } 2114 }
1746 2115
1747 protected void ClearCommand(Object[] args) 2116 protected void HandleClearCommand(string module, string[] args)
1748 { 2117 {
2118 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
2119 return;
2120
1749 string response = MainConsole.Instance.CmdPrompt( 2121 string response = MainConsole.Instance.CmdPrompt(
1750 string.Format( 2122 string.Format(
1751 "Are you sure that you want to clear all land parcels from {0} (y or n)", 2123 "Are you sure that you want to clear all land parcels from {0} (y or n)", m_scene.Name),
1752 m_scene.RegionInfo.RegionName),
1753 "n"); 2124 "n");
1754 2125
1755 if (response.ToLower() == "y") 2126 if (response.ToLower() == "y")
1756 { 2127 {
1757 Clear(true); 2128 Clear(true);
1758 MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.RegionInfo.RegionName); 2129 MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.Name);
1759 } 2130 }
1760 else 2131 else
1761 { 2132 {
1762 MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.RegionInfo.RegionName); 2133 MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.Name);
1763 } 2134 }
1764 } 2135 }
1765 2136
1766 protected void ShowParcelsCommand(Object[] args) 2137 protected void HandleShowCommand(string module, string[] args)
1767 { 2138 {
1768 StringBuilder report = new StringBuilder(); 2139 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
1769 2140 return;
1770 report.AppendFormat("Land information for {0}\n", m_scene.RegionInfo.RegionName); 2141
1771 report.AppendFormat( 2142 StringBuilder report = new StringBuilder();
1772 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", 2143
1773 "Parcel Name", 2144 if (args.Length <= 2)
1774 "Local ID", 2145 {
1775 "Area", 2146 AppendParcelsSummaryReport(report);
1776 "Starts", 2147 }
1777 "Ends", 2148 else
1778 "Owner"); 2149 {
2150 int landLocalId;
2151
2152 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[2], out landLocalId))
2153 return;
2154
2155 ILandObject lo;
2156
2157 lock (m_landList)
2158 {
2159 if (!m_landList.TryGetValue(landLocalId, out lo))
2160 {
2161 MainConsole.Instance.OutputFormat("No parcel found with local ID {0}", landLocalId);
2162 return;
2163 }
2164 }
2165
2166 AppendParcelReport(report, lo);
2167 }
2168
2169 MainConsole.Instance.Output(report.ToString());
2170 }
2171
2172 private void AppendParcelsSummaryReport(StringBuilder report)
2173 {
2174 report.AppendFormat("Land information for {0}\n", m_scene.Name);
2175
2176 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
2177 cdt.AddColumn("Parcel Name", ConsoleDisplayUtil.ParcelNameSize);
2178 cdt.AddColumn("ID", 3);
2179 cdt.AddColumn("Area", 6);
2180 cdt.AddColumn("Starts", ConsoleDisplayUtil.VectorSize);
2181 cdt.AddColumn("Ends", ConsoleDisplayUtil.VectorSize);
2182 cdt.AddColumn("Owner", ConsoleDisplayUtil.UserNameSize);
1779 2183
1780 lock (m_landList) 2184 lock (m_landList)
1781 { 2185 {
1782 foreach (ILandObject lo in m_landList.Values) 2186 foreach (ILandObject lo in m_landList.Values)
1783 { 2187 {
1784 LandData ld = lo.LandData; 2188 LandData ld = lo.LandData;
1785 2189 string ownerName;
1786 report.AppendFormat( 2190 if (ld.IsGroupOwned)
1787 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", 2191 {
1788 ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, m_userManager.GetUserName(ld.OwnerID)); 2192 GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
2193 ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
2194 }
2195 else
2196 {
2197 ownerName = m_userManager.GetUserName(ld.OwnerID);
2198 }
2199 cdt.AddRow(
2200 ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, ownerName);
1789 } 2201 }
1790 } 2202 }
1791 2203
1792 MainConsole.Instance.Output(report.ToString()); 2204 report.Append(cdt.ToString());
1793 } 2205 }
2206
2207 private void AppendParcelReport(StringBuilder report, ILandObject lo)
2208 {
2209 LandData ld = lo.LandData;
2210
2211 ConsoleDisplayList cdl = new ConsoleDisplayList();
2212 cdl.AddRow("Parcel name", ld.Name);
2213 cdl.AddRow("Local ID", ld.LocalID);
2214 cdl.AddRow("Description", ld.Description);
2215 cdl.AddRow("Snapshot ID", ld.SnapshotID);
2216 cdl.AddRow("Area", ld.Area);
2217 cdl.AddRow("Starts", lo.StartPoint);
2218 cdl.AddRow("Ends", lo.EndPoint);
2219 cdl.AddRow("AABB Min", ld.AABBMin);
2220 cdl.AddRow("AABB Max", ld.AABBMax);
2221 string ownerName;
2222 if (ld.IsGroupOwned)
2223 {
2224 GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
2225 ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
2226 }
2227 else
2228 {
2229 ownerName = m_userManager.GetUserName(ld.OwnerID);
2230 }
2231 cdl.AddRow("Owner", ownerName);
2232 cdl.AddRow("Is group owned?", ld.IsGroupOwned);
2233 cdl.AddRow("GroupID", ld.GroupID);
2234
2235 cdl.AddRow("Status", ld.Status);
2236 cdl.AddRow("Flags", (ParcelFlags)ld.Flags);
2237
2238 cdl.AddRow("Landing Type", (LandingType)ld.LandingType);
2239 cdl.AddRow("User Location", ld.UserLocation);
2240 cdl.AddRow("User look at", ld.UserLookAt);
2241
2242 cdl.AddRow("Other clean time", ld.OtherCleanTime);
2243
2244 cdl.AddRow("Max Prims", lo.GetParcelMaxPrimCount());
2245 IPrimCounts pc = lo.PrimCounts;
2246 cdl.AddRow("Owner Prims", pc.Owner);
2247 cdl.AddRow("Group Prims", pc.Group);
2248 cdl.AddRow("Other Prims", pc.Others);
2249 cdl.AddRow("Selected Prims", pc.Selected);
2250 cdl.AddRow("Total Prims", pc.Total);
2251
2252 cdl.AddRow("Music URL", ld.MusicURL);
2253 cdl.AddRow("Obscure Music", ld.ObscureMusic);
2254
2255 cdl.AddRow("Media ID", ld.MediaID);
2256 cdl.AddRow("Media Autoscale", Convert.ToBoolean(ld.MediaAutoScale));
2257 cdl.AddRow("Media URL", ld.MediaURL);
2258 cdl.AddRow("Media Type", ld.MediaType);
2259 cdl.AddRow("Media Description", ld.MediaDescription);
2260 cdl.AddRow("Media Width", ld.MediaWidth);
2261 cdl.AddRow("Media Height", ld.MediaHeight);
2262 cdl.AddRow("Media Loop", ld.MediaLoop);
2263 cdl.AddRow("Obscure Media", ld.ObscureMedia);
2264
2265 cdl.AddRow("Parcel Category", ld.Category);
2266
2267 cdl.AddRow("Claim Date", ld.ClaimDate);
2268 cdl.AddRow("Claim Price", ld.ClaimPrice);
2269 cdl.AddRow("Pass Hours", ld.PassHours);
2270 cdl.AddRow("Pass Price", ld.PassPrice);
2271
2272 cdl.AddRow("Auction ID", ld.AuctionID);
2273 cdl.AddRow("Authorized Buyer ID", ld.AuthBuyerID);
2274 cdl.AddRow("Sale Price", ld.SalePrice);
2275
2276 cdl.AddToStringBuilder(report);
2277 }
1794 } 2278 }
1795} 2279}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index 5969d45..a0c1b9d 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -45,14 +45,12 @@ namespace OpenSim.Region.CoreModules.World.Land
45 #region Member Variables 45 #region Member Variables
46 46
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 #pragma warning disable 0429 48 private static readonly string LogHeader = "[LAND OBJECT]";
49 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
50 #pragma warning restore 0429
51 private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax];
52 49
53 private int m_lastSeqId = 0; 50 private readonly int landUnit = 4;
54 51
55 protected LandData m_landData = new LandData(); 52 private int m_lastSeqId = 0;
53
56 protected Scene m_scene; 54 protected Scene m_scene;
57 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); 55 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
58 protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); 56 protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>();
@@ -60,76 +58,83 @@ namespace OpenSim.Region.CoreModules.World.Land
60 protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); 58 protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>();
61 protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds 59 protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds
62 60
63 public bool[,] LandBitmap 61 public bool[,] LandBitmap { get; set; }
64 {
65 get { return m_landBitmap; }
66 set { m_landBitmap = value; }
67 }
68 62
69 #endregion 63 #endregion
70 64
71 public int GetPrimsFree() 65 public int GetPrimsFree()
72 { 66 {
73 m_scene.EventManager.TriggerParcelPrimCountUpdate(); 67 m_scene.EventManager.TriggerParcelPrimCountUpdate();
74 int free = GetSimulatorMaxPrimCount() - m_landData.SimwidePrims; 68 int free = GetSimulatorMaxPrimCount() - LandData.SimwidePrims;
75 return free; 69 return free;
76 } 70 }
77 71
78 public LandData LandData 72 public LandData LandData { get; set; }
79 {
80 get { return m_landData; }
81 73
82 set { m_landData = value; }
83 }
84
85 public IPrimCounts PrimCounts { get; set; } 74 public IPrimCounts PrimCounts { get; set; }
86 75
87 public UUID RegionUUID 76 public UUID RegionUUID
88 { 77 {
89 get { return m_scene.RegionInfo.RegionID; } 78 get { return m_scene.RegionInfo.RegionID; }
90 } 79 }
91 80
92 public Vector3 StartPoint 81 public Vector3 StartPoint
93 { 82 {
94 get 83 get
95 { 84 {
96 for (int y = 0; y < landArrayMax; y++) 85 for (int y = 0; y < LandBitmap.GetLength(1); y++)
97 { 86 {
98 for (int x = 0; x < landArrayMax; x++) 87 for (int x = 0; x < LandBitmap.GetLength(0); x++)
99 { 88 {
100 if (LandBitmap[x, y]) 89 if (LandBitmap[x, y])
101 return new Vector3(x * 4, y * 4, 0); 90 return new Vector3(x * landUnit, y * landUnit, 0);
102 } 91 }
103 } 92 }
104 93
94 m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>",
95 LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
105 return new Vector3(-1, -1, -1); 96 return new Vector3(-1, -1, -1);
106 } 97 }
107 } 98 }
108 99
109 public Vector3 EndPoint 100 public Vector3 EndPoint
110 { 101 {
111 get 102 get
112 { 103 {
113 for (int y = landArrayMax - 1; y >= 0; y--) 104 for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--)
114 { 105 {
115 for (int x = landArrayMax - 1; x >= 0; x--) 106 for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--)
116 { 107 {
117 if (LandBitmap[x, y]) 108 if (LandBitmap[x, y])
118 { 109 {
119 return new Vector3(x * 4, y * 4, 0); 110 return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
120 } 111 }
121 } 112 }
122 } 113 }
123 114
115 m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>",
116 LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
124 return new Vector3(-1, -1, -1); 117 return new Vector3(-1, -1, -1);
125 } 118 }
126 } 119 }
127 120
128 #region Constructors 121 #region Constructors
129 122
123 public LandObject(LandData landData, Scene scene)
124 {
125 LandData = landData.Copy();
126 m_scene = scene;
127 }
128
130 public LandObject(UUID owner_id, bool is_group_owned, Scene scene) 129 public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
131 { 130 {
132 m_scene = scene; 131 m_scene = scene;
132 if (m_scene == null)
133 LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
134 else
135 LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
136
137 LandData = new LandData();
133 LandData.OwnerID = owner_id; 138 LandData.OwnerID = owner_id;
134 if (is_group_owned) 139 if (is_group_owned)
135 LandData.GroupID = owner_id; 140 LandData.GroupID = owner_id;
@@ -152,9 +157,9 @@ namespace OpenSim.Region.CoreModules.World.Land
152 /// <returns>Returns true if the piece of land contains the specified point</returns> 157 /// <returns>Returns true if the piece of land contains the specified point</returns>
153 public bool ContainsPoint(int x, int y) 158 public bool ContainsPoint(int x, int y)
154 { 159 {
155 if (x >= 0 && y >= 0 && x < Constants.RegionSize && y < Constants.RegionSize) 160 if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
156 { 161 {
157 return (LandBitmap[x / 4, y / 4] == true); 162 return LandBitmap[x / landUnit, y / landUnit];
158 } 163 }
159 else 164 else
160 { 165 {
@@ -164,12 +169,8 @@ namespace OpenSim.Region.CoreModules.World.Land
164 169
165 public ILandObject Copy() 170 public ILandObject Copy()
166 { 171 {
167 ILandObject newLand = new LandObject(LandData.OwnerID, LandData.IsGroupOwned, m_scene); 172 ILandObject newLand = new LandObject(LandData, m_scene);
168
169 //Place all new variables here!
170 newLand.LandBitmap = (bool[,]) (LandBitmap.Clone()); 173 newLand.LandBitmap = (bool[,]) (LandBitmap.Clone());
171 newLand.LandData = LandData.Copy();
172
173 return newLand; 174 return newLand;
174 } 175 }
175 176
@@ -194,7 +195,7 @@ namespace OpenSim.Region.CoreModules.World.Land
194 else 195 else
195 { 196 {
196 // Normal Calculations 197 // Normal Calculations
197 int parcelMax = (int)(((float)LandData.Area / 65536.0f) 198 int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
198 * (float)m_scene.RegionInfo.ObjectCapacity 199 * (float)m_scene.RegionInfo.ObjectCapacity
199 * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 200 * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus);
200 // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! 201 // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL!
@@ -211,7 +212,7 @@ namespace OpenSim.Region.CoreModules.World.Land
211 else 212 else
212 { 213 {
213 //Normal Calculations 214 //Normal Calculations
214 int simMax = (int)(((float)LandData.SimwideArea / 65536.0f) 215 int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
215 * (float)m_scene.RegionInfo.ObjectCapacity); 216 * (float)m_scene.RegionInfo.ObjectCapacity);
216 return simMax; 217 return simMax;
217 } 218 }
@@ -224,17 +225,15 @@ namespace OpenSim.Region.CoreModules.World.Land
224 public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) 225 public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
225 { 226 {
226 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); 227 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
227 uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); 228 // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
229 uint regionFlags = (uint)(RegionFlags.PublicAllowed
230 | RegionFlags.AllowDirectTeleport
231 | RegionFlags.AllowParcelChanges
232 | RegionFlags.AllowVoice );
233
228 if (estateModule != null) 234 if (estateModule != null)
229 regionFlags = estateModule.GetRegionFlags(); 235 regionFlags = estateModule.GetRegionFlags();
230 236
231 // In a perfect world, this would have worked.
232 //
233// if ((landData.Flags & (uint)ParcelFlags.AllowLandmark) != 0)
234// regionFlags |= (uint)RegionFlags.AllowLandmark;
235// if (landData.OwnerID == remote_client.AgentId)
236// regionFlags |= (uint)RegionFlags.AllowSetHome;
237
238 int seq_id; 237 int seq_id;
239 if (snap_selection && (sequence_id == 0)) 238 if (snap_selection && (sequence_id == 0))
240 { 239 {
@@ -368,12 +367,14 @@ namespace OpenSim.Region.CoreModules.World.Land
368 ParcelFlags.DenyAgeUnverified); 367 ParcelFlags.DenyAgeUnverified);
369 } 368 }
370 369
371 uint preserve = LandData.Flags & ~allowedDelta; 370 if (allowedDelta != (uint)ParcelFlags.None)
372 newData.Flags = preserve | (args.ParcelFlags & allowedDelta); 371 {
373 372 uint preserve = LandData.Flags & ~allowedDelta;
374 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); 373 newData.Flags = preserve | (args.ParcelFlags & allowedDelta);
375 374
376 SendLandUpdateToAvatarsOverMe(snap_selection); 375 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
376 SendLandUpdateToAvatarsOverMe(snap_selection);
377 }
377 } 378 }
378 379
379 public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) 380 public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
@@ -388,9 +389,16 @@ namespace OpenSim.Region.CoreModules.World.Land
388 newData.SalePrice = 0; 389 newData.SalePrice = 0;
389 newData.AuthBuyerID = UUID.Zero; 390 newData.AuthBuyerID = UUID.Zero;
390 newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); 391 newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
392
393 bool sellObjects = (LandData.Flags & (uint)(ParcelFlags.SellParcelObjects)) != 0
394 && !LandData.IsGroupOwned && !groupOwned;
395 UUID previousOwner = LandData.OwnerID;
396
391 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); 397 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
392 m_scene.EventManager.TriggerParcelPrimCountUpdate(); 398 m_scene.EventManager.TriggerParcelPrimCountUpdate();
393 SendLandUpdateToAvatarsOverMe(true); 399 SendLandUpdateToAvatarsOverMe(true);
400
401 if (sellObjects) SellLandObjects(previousOwner);
394 } 402 }
395 403
396 public void DeedToGroup(UUID groupID) 404 public void DeedToGroup(UUID groupID)
@@ -421,6 +429,19 @@ namespace OpenSim.Region.CoreModules.World.Land
421 return false; 429 return false;
422 } 430 }
423 431
432 public bool CanBeOnThisLand(UUID avatar, float posHeight)
433 {
434 if (posHeight < LandChannel.BAN_LINE_SAFETY_HIEGHT && IsBannedFromLand(avatar))
435 {
436 return false;
437 }
438 else if (IsRestrictedFromLand(avatar))
439 {
440 return false;
441 }
442 return true;
443 }
444
424 public bool HasGroupAccess(UUID avatar) 445 public bool HasGroupAccess(UUID avatar)
425 { 446 {
426 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup) 447 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
@@ -553,8 +574,8 @@ namespace OpenSim.Region.CoreModules.World.Land
553 try 574 try
554 { 575 {
555 over = 576 over =
556 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), 577 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
557 Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); 578 Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
558 } 579 }
559 catch (Exception) 580 catch (Exception)
560 { 581 {
@@ -701,15 +722,15 @@ namespace OpenSim.Region.CoreModules.World.Land
701 /// </summary> 722 /// </summary>
702 private void UpdateAABBAndAreaValues() 723 private void UpdateAABBAndAreaValues()
703 { 724 {
704 int min_x = 64; 725 int min_x = 10000;
705 int min_y = 64; 726 int min_y = 10000;
706 int max_x = 0; 727 int max_x = 0;
707 int max_y = 0; 728 int max_y = 0;
708 int tempArea = 0; 729 int tempArea = 0;
709 int x, y; 730 int x, y;
710 for (x = 0; x < 64; x++) 731 for (x = 0; x < LandBitmap.GetLength(0); x++)
711 { 732 {
712 for (y = 0; y < 64; y++) 733 for (y = 0; y < LandBitmap.GetLength(1); y++)
713 { 734 {
714 if (LandBitmap[x, y] == true) 735 if (LandBitmap[x, y] == true)
715 { 736 {
@@ -717,31 +738,31 @@ namespace OpenSim.Region.CoreModules.World.Land
717 if (min_y > y) min_y = y; 738 if (min_y > y) min_y = y;
718 if (max_x < x) max_x = x; 739 if (max_x < x) max_x = x;
719 if (max_y < y) max_y = y; 740 if (max_y < y) max_y = y;
720 tempArea += 16; //16sqm peice of land 741 tempArea += landUnit * landUnit; //16sqm peice of land
721 } 742 }
722 } 743 }
723 } 744 }
724 int tx = min_x * 4; 745 int tx = min_x * landUnit;
725 if (tx > ((int)Constants.RegionSize - 1)) 746 if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
726 tx = ((int)Constants.RegionSize - 1); 747 tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
727 int ty = min_y * 4; 748 int ty = min_y * landUnit;
728 if (ty > ((int)Constants.RegionSize - 1)) 749 if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
729 ty = ((int)Constants.RegionSize - 1); 750 ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
730 751
731 LandData.AABBMin = 752 LandData.AABBMin =
732 new Vector3( 753 new Vector3(
733 (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); 754 (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
734 755
735 tx = max_x * 4; 756 tx = max_x * landUnit;
736 if (tx > ((int)Constants.RegionSize - 1)) 757 if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
737 tx = ((int)Constants.RegionSize - 1); 758 tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
738 ty = max_y * 4; 759 ty = max_y * landUnit;
739 if (ty > ((int)Constants.RegionSize - 1)) 760 if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
740 ty = ((int)Constants.RegionSize - 1); 761 ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
741 762
742 LandData.AABBMax 763 LandData.AABBMax
743 = new Vector3( 764 = new Vector3(
744 (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); 765 (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
745 766
746 LandData.Area = tempArea; 767 LandData.Area = tempArea;
747 } 768 }
@@ -753,20 +774,12 @@ namespace OpenSim.Region.CoreModules.World.Land
753 /// <summary> 774 /// <summary>
754 /// Sets the land's bitmap manually 775 /// Sets the land's bitmap manually
755 /// </summary> 776 /// </summary>
756 /// <param name="bitmap">64x64 block representing where this land is on a map</param> 777 /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
757 public void SetLandBitmap(bool[,] bitmap) 778 public void SetLandBitmap(bool[,] bitmap)
758 { 779 {
759 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) 780 LandBitmap = bitmap;
760 { 781 // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
761 //Throw an exception - The bitmap is not 64x64 782 ForceUpdateLandInfo();
762 //throw new Exception("Error: Invalid Parcel Bitmap");
763 }
764 else
765 {
766 //Valid: Lets set it
767 LandBitmap = bitmap;
768 ForceUpdateLandInfo();
769 }
770 } 783 }
771 784
772 /// <summary> 785 /// <summary>
@@ -780,15 +793,19 @@ namespace OpenSim.Region.CoreModules.World.Land
780 793
781 public bool[,] BasicFullRegionLandBitmap() 794 public bool[,] BasicFullRegionLandBitmap()
782 { 795 {
783 return GetSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize); 796 return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY);
784 } 797 }
785 798
786 public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) 799 public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
787 { 800 {
788 bool[,] tempBitmap = new bool[64,64]; 801 // Empty bitmap for the whole region
802 bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
789 tempBitmap.Initialize(); 803 tempBitmap.Initialize();
790 804
805 // Fill the bitmap square area specified by state and end
791 tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); 806 tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
807 // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>",
808 // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1));
792 return tempBitmap; 809 return tempBitmap;
793 } 810 }
794 811
@@ -805,24 +822,20 @@ namespace OpenSim.Region.CoreModules.World.Land
805 public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, 822 public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
806 bool set_value) 823 bool set_value)
807 { 824 {
808 if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
809 {
810 //Throw an exception - The bitmap is not 64x64
811 //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
812 }
813
814 int x, y; 825 int x, y;
815 for (y = 0; y < 64; y++) 826 for (y = 0; y < land_bitmap.GetLength(1); y++)
816 { 827 {
817 for (x = 0; x < 64; x++) 828 for (x = 0; x < land_bitmap.GetLength(0); x++)
818 { 829 {
819 if (x >= start_x / 4 && x < end_x / 4 830 if (x >= start_x / landUnit && x < end_x / landUnit
820 && y >= start_y / 4 && y < end_y / 4) 831 && y >= start_y / landUnit && y < end_y / landUnit)
821 { 832 {
822 land_bitmap[x, y] = set_value; 833 land_bitmap[x, y] = set_value;
823 } 834 }
824 } 835 }
825 } 836 }
837 // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>",
838 // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1));
826 return land_bitmap; 839 return land_bitmap;
827 } 840 }
828 841
@@ -834,21 +847,21 @@ namespace OpenSim.Region.CoreModules.World.Land
834 /// <returns></returns> 847 /// <returns></returns>
835 public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) 848 public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
836 { 849 {
837 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) 850 if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
851 || bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
852 || bitmap_add.Rank != 2
853 || bitmap_base.Rank != 2)
838 { 854 {
839 //Throw an exception - The bitmap is not 64x64 855 throw new Exception(
840 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); 856 String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
841 } 857 LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
842 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2) 858 );
843 {
844 //Throw an exception - The bitmap is not 64x64
845 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
846 } 859 }
847 860
848 int x, y; 861 int x, y;
849 for (y = 0; y < 64; y++) 862 for (y = 0; y < bitmap_base.GetLength(1); y++)
850 { 863 {
851 for (x = 0; x < 64; x++) 864 for (x = 0; x < bitmap_add.GetLength(0); x++)
852 { 865 {
853 if (bitmap_add[x, y]) 866 if (bitmap_add[x, y])
854 { 867 {
@@ -865,13 +878,13 @@ namespace OpenSim.Region.CoreModules.World.Land
865 /// <returns></returns> 878 /// <returns></returns>
866 private byte[] ConvertLandBitmapToBytes() 879 private byte[] ConvertLandBitmapToBytes()
867 { 880 {
868 byte[] tempConvertArr = new byte[512]; 881 byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
869 byte tempByte = 0; 882 byte tempByte = 0;
870 int x, y, i, byteNum = 0; 883 int byteNum = 0;
871 i = 0; 884 int i = 0;
872 for (y = 0; y < 64; y++) 885 for (int y = 0; y < LandBitmap.GetLength(1); y++)
873 { 886 {
874 for (x = 0; x < 64; x++) 887 for (int x = 0; x < LandBitmap.GetLength(0); x++)
875 { 888 {
876 tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); 889 tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8));
877 if (i % 8 == 0) 890 if (i % 8 == 0)
@@ -883,30 +896,52 @@ namespace OpenSim.Region.CoreModules.World.Land
883 } 896 }
884 } 897 }
885 } 898 }
899 // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>",
900 // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
886 return tempConvertArr; 901 return tempConvertArr;
887 } 902 }
888 903
889 private bool[,] ConvertBytesToLandBitmap() 904 private bool[,] ConvertBytesToLandBitmap()
890 { 905 {
891 bool[,] tempConvertMap = new bool[landArrayMax, landArrayMax]; 906 bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
892 tempConvertMap.Initialize(); 907 tempConvertMap.Initialize();
893 byte tempByte = 0; 908 byte tempByte = 0;
894 int x = 0, y = 0, i = 0, bitNum = 0; 909 // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
895 for (i = 0; i < 512; i++) 910 int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
911 int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
912
913 if (bitmapLen == 512)
914 {
915 // Legacy bitmap being passed in. Use the legacy region size
916 // and only set the lower area of the larger region.
917 xLen = (int)(Constants.RegionSize / landUnit);
918 }
919 // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
920
921 int x = 0, y = 0;
922 for (int i = 0; i < bitmapLen; i++)
896 { 923 {
897 tempByte = LandData.Bitmap[i]; 924 tempByte = LandData.Bitmap[i];
898 for (bitNum = 0; bitNum < 8; bitNum++) 925 for (int bitNum = 0; bitNum < 8; bitNum++)
899 { 926 {
900 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); 927 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
901 tempConvertMap[x, y] = bit; 928 try
929 {
930 tempConvertMap[x, y] = bit;
931 }
932 catch (Exception)
933 {
934 m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
935 }
902 x++; 936 x++;
903 if (x > 63) 937 if (x >= xLen)
904 { 938 {
905 x = 0; 939 x = 0;
906 y++; 940 y++;
907 } 941 }
908 } 942 }
909 } 943 }
944
910 return tempConvertMap; 945 return tempConvertMap;
911 } 946 }
912 947
@@ -1043,6 +1078,43 @@ namespace OpenSim.Region.CoreModules.World.Land
1043 1078
1044 #endregion 1079 #endregion
1045 1080
1081 #region Object Sales
1082
1083 public void SellLandObjects(UUID previousOwner)
1084 {
1085 // m_log.DebugFormat(
1086 // "[LAND OBJECT]: Request to sell objects in {0} from {1}", LandData.Name, previousOwner);
1087
1088 if (LandData.IsGroupOwned)
1089 return;
1090
1091 IBuySellModule m_BuySellModule = m_scene.RequestModuleInterface<IBuySellModule>();
1092 if (m_BuySellModule == null)
1093 {
1094 m_log.Error("[LAND OBJECT]: BuySellModule not found");
1095 return;
1096 }
1097
1098 ScenePresence sp;
1099 if (!m_scene.TryGetScenePresence(LandData.OwnerID, out sp))
1100 {
1101 m_log.Error("[LAND OBJECT]: New owner is not present in scene");
1102 return;
1103 }
1104
1105 lock (primsOverMe)
1106 {
1107 foreach (SceneObjectGroup obj in primsOverMe)
1108 {
1109 if (obj.OwnerID == previousOwner && obj.GroupID == UUID.Zero &&
1110 (obj.GetEffectivePermissions() & (uint)(OpenSim.Framework.PermissionMask.Transfer)) != 0)
1111 m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, 1, 0);
1112 }
1113 }
1114 }
1115
1116 #endregion
1117
1046 #region Object Returning 1118 #region Object Returning
1047 1119
1048 public void ReturnObject(SceneObjectGroup obj) 1120 public void ReturnObject(SceneObjectGroup obj)
@@ -1065,7 +1137,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1065 { 1137 {
1066 foreach (SceneObjectGroup obj in primsOverMe) 1138 foreach (SceneObjectGroup obj in primsOverMe)
1067 { 1139 {
1068 if (obj.OwnerID == m_landData.OwnerID) 1140 if (obj.OwnerID == LandData.OwnerID)
1069 { 1141 {
1070 if (!returns.ContainsKey(obj.OwnerID)) 1142 if (!returns.ContainsKey(obj.OwnerID))
1071 returns[obj.OwnerID] = 1143 returns[obj.OwnerID] =
@@ -1074,11 +1146,11 @@ namespace OpenSim.Region.CoreModules.World.Land
1074 } 1146 }
1075 } 1147 }
1076 } 1148 }
1077 else if (type == (uint)ObjectReturnType.Group && m_landData.GroupID != UUID.Zero) 1149 else if (type == (uint)ObjectReturnType.Group && LandData.GroupID != UUID.Zero)
1078 { 1150 {
1079 foreach (SceneObjectGroup obj in primsOverMe) 1151 foreach (SceneObjectGroup obj in primsOverMe)
1080 { 1152 {
1081 if (obj.GroupID == m_landData.GroupID) 1153 if (obj.GroupID == LandData.GroupID)
1082 { 1154 {
1083 if (!returns.ContainsKey(obj.OwnerID)) 1155 if (!returns.ContainsKey(obj.OwnerID))
1084 returns[obj.OwnerID] = 1156 returns[obj.OwnerID] =
@@ -1091,9 +1163,9 @@ namespace OpenSim.Region.CoreModules.World.Land
1091 { 1163 {
1092 foreach (SceneObjectGroup obj in primsOverMe) 1164 foreach (SceneObjectGroup obj in primsOverMe)
1093 { 1165 {
1094 if (obj.OwnerID != m_landData.OwnerID && 1166 if (obj.OwnerID != LandData.OwnerID &&
1095 (obj.GroupID != m_landData.GroupID || 1167 (obj.GroupID != LandData.GroupID ||
1096 m_landData.GroupID == UUID.Zero)) 1168 LandData.GroupID == UUID.Zero))
1097 { 1169 {
1098 if (!returns.ContainsKey(obj.OwnerID)) 1170 if (!returns.ContainsKey(obj.OwnerID))
1099 returns[obj.OwnerID] = 1171 returns[obj.OwnerID] =
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
index f9cc0cf..9b51cc8 100644
--- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
@@ -490,11 +490,14 @@ namespace OpenSim.Region.CoreModules.World.Land
490 490
491 m_Scene.ForEachSOG(AddObject); 491 m_Scene.ForEachSOG(AddObject);
492 492
493 List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys); 493 lock (m_PrimCounts)
494 foreach (UUID k in primcountKeys)
495 { 494 {
496 if (!m_OwnerMap.ContainsKey(k)) 495 List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys);
497 m_PrimCounts.Remove(k); 496 foreach (UUID k in primcountKeys)
497 {
498 if (!m_OwnerMap.ContainsKey(k))
499 m_PrimCounts.Remove(k);
500 }
498 } 501 }
499 502
500 m_Tainted = false; 503 m_Tainted = false;
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs
new file mode 100644
index 0000000..4ed67f3
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs
@@ -0,0 +1,266 @@
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
28using System;
29using NUnit.Framework;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Tests.Common;
34
35namespace OpenSim.Region.CoreModules.World.Land.Tests
36{
37 public class LandManagementModuleTests : OpenSimTestCase
38 {
39 [Test]
40 public void TestAddLandObject()
41 {
42 TestHelpers.InMethod();
43// TestHelpers.EnableLogging();
44
45 UUID userId = TestHelpers.ParseTail(0x1);
46
47 LandManagementModule lmm = new LandManagementModule();
48 Scene scene = new SceneHelpers().SetupScene();
49 SceneHelpers.SetupSceneModules(scene, lmm);
50
51 ILandObject lo = new LandObject(userId, false, scene);
52 lo.LandData.Name = "lo1";
53 lo.SetLandBitmap(
54 lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
55 lo = lmm.AddLandObject(lo);
56
57 // TODO: Should add asserts to check that land object was added properly.
58
59 // At the moment, this test just makes sure that we can't add a land object that overlaps the areas that
60 // the first still holds.
61 ILandObject lo2 = new LandObject(userId, false, scene);
62 lo2.SetLandBitmap(
63 lo2.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
64 lo2.LandData.Name = "lo2";
65 lo2 = lmm.AddLandObject(lo2);
66
67 {
68 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
69 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
70 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
71 }
72
73 {
74 ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
75 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
76 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
77 }
78 }
79
80 /// <summary>
81 /// Test parcels on region when no land data exists to be loaded.
82 /// </summary>
83 [Test]
84 public void TestLoadWithNoParcels()
85 {
86 TestHelpers.InMethod();
87// TestHelpers.EnableLogging();
88
89 SceneHelpers sh = new SceneHelpers();
90 LandManagementModule lmm = new LandManagementModule();
91 Scene scene = sh.SetupScene();
92 SceneHelpers.SetupSceneModules(scene, lmm);
93
94 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
95
96 ILandObject loAtCoord1 = lmm.GetLandObject(0, 0);
97 Assert.That(loAtCoord1.LandData.LocalID, Is.Not.EqualTo(0));
98 Assert.That(loAtCoord1.LandData.GlobalID, Is.Not.EqualTo(UUID.Zero));
99
100 ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
101 Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID));
102 Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID));
103 }
104
105 /// <summary>
106 /// Test parcels on region when a single parcel already exists but it does not cover the whole region.
107 /// </summary>
108 [Test]
109 public void TestLoadWithSinglePartialCoveringParcel()
110 {
111 TestHelpers.InMethod();
112// TestHelpers.EnableLogging();
113
114 UUID userId = TestHelpers.ParseTail(0x1);
115
116 SceneHelpers sh = new SceneHelpers();
117 LandManagementModule lmm = new LandManagementModule();
118 Scene scene = sh.SetupScene();
119 SceneHelpers.SetupSceneModules(scene, lmm);
120
121 ILandObject originalLo1 = new LandObject(userId, false, scene);
122 originalLo1.LandData.Name = "lo1";
123 originalLo1.SetLandBitmap(
124 originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2));
125
126 sh.SimDataService.StoreLandObject(originalLo1);
127
128 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
129
130 ILandObject loAtCoord1 = lmm.GetLandObject(0, 0);
131 Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name));
132 Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID));
133
134 ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
135 Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID));
136 Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID));
137 }
138
139 /// <summary>
140 /// Test parcels on region when a single parcel already exists but it does not cover the whole region.
141 /// </summary>
142 [Test]
143 public void TestLoadWithMultiplePartialCoveringParcels()
144 {
145 TestHelpers.InMethod();
146// TestHelpers.EnableLogging();
147
148 UUID userId = TestHelpers.ParseTail(0x1);
149
150 SceneHelpers sh = new SceneHelpers();
151 LandManagementModule lmm = new LandManagementModule();
152 Scene scene = sh.SetupScene();
153 SceneHelpers.SetupSceneModules(scene, lmm);
154
155 ILandObject originalLo1 = new LandObject(userId, false, scene);
156 originalLo1.LandData.Name = "lo1";
157 originalLo1.SetLandBitmap(
158 originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2));
159
160 sh.SimDataService.StoreLandObject(originalLo1);
161
162 ILandObject originalLo2 = new LandObject(userId, false, scene);
163 originalLo2.LandData.Name = "lo2";
164 originalLo2.SetLandBitmap(
165 originalLo2.GetSquareLandBitmap(
166 0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, ((int)Constants.RegionSize / 4) * 3));
167
168 sh.SimDataService.StoreLandObject(originalLo2);
169
170 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
171
172 ILandObject loAtCoord1 = lmm.GetLandObject(0, 0);
173 Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name));
174 Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID));
175
176 ILandObject loAtCoord2
177 = lmm.GetLandObject((int)Constants.RegionSize - 1, (((int)Constants.RegionSize / 4) * 3) - 1);
178 Assert.That(loAtCoord2.LandData.Name, Is.EqualTo(originalLo2.LandData.Name));
179 Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID));
180
181 ILandObject loAtCoord3 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
182 Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord1.LandData.LocalID));
183 Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord2.LandData.LocalID));
184 Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord1.LandData.GlobalID));
185 Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord2.LandData.GlobalID));
186 }
187
188 /// <summary>
189 /// Test parcels on region when whole region is parcelled (which should normally always be the case).
190 /// </summary>
191 [Test]
192 public void TestLoad()
193 {
194 TestHelpers.InMethod();
195// TestHelpers.EnableLogging();
196
197 UUID userId = TestHelpers.ParseTail(0x1);
198
199 SceneHelpers sh = new SceneHelpers();
200 LandManagementModule lmm = new LandManagementModule();
201 Scene scene = sh.SetupScene();
202 SceneHelpers.SetupSceneModules(scene, lmm);
203
204 ILandObject originalLo1 = new LandObject(userId, false, scene);
205 originalLo1.LandData.Name = "lo1";
206 originalLo1.SetLandBitmap(
207 originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2));
208
209 sh.SimDataService.StoreLandObject(originalLo1);
210
211 ILandObject originalLo2 = new LandObject(userId, false, scene);
212 originalLo2.LandData.Name = "lo2";
213 originalLo2.SetLandBitmap(
214 originalLo2.GetSquareLandBitmap(0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, (int)Constants.RegionSize));
215
216 sh.SimDataService.StoreLandObject(originalLo2);
217
218 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
219
220 {
221 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
222 Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo1.LandData.Name));
223 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID));
224 }
225
226 {
227 ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
228 Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo2.LandData.Name));
229 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID));
230 }
231 }
232
233 [Test]
234 public void TestSubdivide()
235 {
236 TestHelpers.InMethod();
237// TestHelpers.EnableLogging();
238
239 UUID userId = TestHelpers.ParseTail(0x1);
240
241 LandManagementModule lmm = new LandManagementModule();
242 Scene scene = new SceneHelpers().SetupScene();
243 SceneHelpers.SetupSceneModules(scene, lmm);
244
245 ILandObject lo = new LandObject(userId, false, scene);
246 lo.LandData.Name = "lo1";
247 lo.SetLandBitmap(
248 lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
249 lo = lmm.AddLandObject(lo);
250
251 lmm.Subdivide(0, 0, LandManagementModule.LandUnit, LandManagementModule.LandUnit, userId);
252
253 {
254 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
255 Assert.That(loAtCoord.LandData.LocalID, Is.Not.EqualTo(lo.LandData.LocalID));
256 Assert.That(loAtCoord.LandData.GlobalID, Is.Not.EqualTo(lo.LandData.GlobalID));
257 }
258
259 {
260 ILandObject loAtCoord = lmm.GetLandObject(LandManagementModule.LandUnit, LandManagementModule.LandUnit);
261 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
262 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
263 }
264 }
265 }
266} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
index 0945b43..949acb6 100644
--- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
+++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
@@ -36,7 +36,6 @@ using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
39using OpenSim.Tests.Common.Mock;
40 39
41namespace OpenSim.Region.CoreModules.World.Land.Tests 40namespace OpenSim.Region.CoreModules.World.Land.Tests
42{ 41{
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
index 8a422b0..796a15f 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
@@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
55 public struct DrawStruct 55 public struct DrawStruct
56 { 56 {
57 public DrawRoutine dr; 57 public DrawRoutine dr;
58 public Rectangle rect; 58// public Rectangle rect;
59 public SolidBrush brush; 59 public SolidBrush brush;
60 public face[] trns; 60 public face[] trns;
61 } 61 }
@@ -77,40 +77,71 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
77 { 77 {
78 bool drawPrimVolume = true; 78 bool drawPrimVolume = true;
79 bool textureTerrain = false; 79 bool textureTerrain = false;
80 bool generateMaptiles = true;
81 Bitmap mapbmp;
80 82
81 try 83 string[] configSections = new string[] { "Map", "Startup" };
82 {
83 IConfig startupConfig = m_config.Configs["Startup"];
84 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume);
85 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain);
86 }
87 catch
88 {
89 m_log.Warn("[MAPTILE]: Failed to load StartupConfig");
90 }
91 84
92 if (textureTerrain) 85 drawPrimVolume
93 { 86 = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume);
94 terrainRenderer = new TexturedMapTileRenderer(); 87 textureTerrain
95 } 88 = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain);
96 else 89 generateMaptiles
90 = Util.GetConfigVarFromSections<bool>(m_config, "GenerateMaptiles", configSections, generateMaptiles);
91
92 if (generateMaptiles)
97 { 93 {
98 terrainRenderer = new ShadedMapTileRenderer(); 94 if (String.IsNullOrEmpty(m_scene.RegionInfo.MaptileStaticFile))
99 } 95 {
100 terrainRenderer.Initialise(m_scene, m_config); 96 if (textureTerrain)
97 {
98 terrainRenderer = new TexturedMapTileRenderer();
99 }
100 else
101 {
102 terrainRenderer = new ShadedMapTileRenderer();
103 }
104
105 terrainRenderer.Initialise(m_scene, m_config);
101 106
102 Bitmap mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 107 mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height,
103 //long t = System.Environment.TickCount; 108 System.Drawing.Imaging.PixelFormat.Format24bppRgb);
104 //for (int i = 0; i < 10; ++i) { 109 //long t = System.Environment.TickCount;
105 terrainRenderer.TerrainToBitmap(mapbmp); 110 //for (int i = 0; i < 10; ++i) {
106 //} 111 terrainRenderer.TerrainToBitmap(mapbmp);
107 //t = System.Environment.TickCount - t; 112 //}
108 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t); 113 //t = System.Environment.TickCount - t;
114 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t);
109 115
116 if (drawPrimVolume)
117 {
118 DrawObjectVolume(m_scene, mapbmp);
119 }
120 }
121 else
122 {
123 try
124 {
125 mapbmp = new Bitmap(m_scene.RegionInfo.MaptileStaticFile);
126 }
127 catch (Exception)
128 {
129 m_log.ErrorFormat(
130 "[MAPTILE]: Failed to load Static map image texture file: {0} for {1}",
131 m_scene.RegionInfo.MaptileStaticFile, m_scene.Name);
132 //mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
133 mapbmp = null;
134 }
110 135
111 if (drawPrimVolume) 136 if (mapbmp != null)
137 m_log.DebugFormat(
138 "[MAPTILE]: Static map image texture file {0} found for {1}",
139 m_scene.RegionInfo.MaptileStaticFile, m_scene.Name);
140 }
141 }
142 else
112 { 143 {
113 DrawObjectVolume(m_scene, mapbmp); 144 mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID);
114 } 145 }
115 146
116 return mapbmp; 147 return mapbmp;
@@ -121,7 +152,10 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
121 try 152 try
122 { 153 {
123 using (Bitmap mapbmp = CreateMapTile()) 154 using (Bitmap mapbmp = CreateMapTile())
124 return OpenJPEG.EncodeFromImage(mapbmp, true); 155 {
156 if (mapbmp != null)
157 return OpenJPEG.EncodeFromImage(mapbmp, true);
158 }
125 } 159 }
126 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke 160 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
127 { 161 {
@@ -139,9 +173,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
139 { 173 {
140 m_config = source; 174 m_config = source;
141 175
142 IConfig startupConfig = m_config.Configs["Startup"]; 176 if (Util.GetConfigVarFromSections<string>(
143 if (startupConfig.GetString("MapImageModule", "MapImageModule") != 177 m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "MapImageModule")
144 "MapImageModule")
145 return; 178 return;
146 179
147 m_Enabled = true; 180 m_Enabled = true;
@@ -222,342 +255,395 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
222// } 255// }
223// } 256// }
224 257
258 private Bitmap FetchTexture(UUID id)
259 {
260 AssetBase asset = m_scene.AssetService.Get(id.ToString());
261
262 if (asset != null)
263 {
264 m_log.DebugFormat("[MAPTILE]: Static map image texture {0} found for {1}", id, m_scene.Name);
265 }
266 else
267 {
268 m_log.WarnFormat("[MAPTILE]: Static map image texture {0} not found for {1}", id, m_scene.Name);
269 return null;
270 }
271
272 ManagedImage managedImage;
273 Image image;
274
275 try
276 {
277 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
278 return new Bitmap(image);
279 else
280 return null;
281 }
282 catch (DllNotFoundException)
283 {
284 m_log.ErrorFormat("[MAPTILE]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id);
285
286 }
287 catch (IndexOutOfRangeException)
288 {
289 m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id);
290
291 }
292 catch (Exception)
293 {
294 m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id);
295
296 }
297 return null;
298
299 }
300
225 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) 301 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
226 { 302 {
227 int tc = 0; 303 int tc = 0;
228 double[,] hm = whichScene.Heightmap.GetDoubles(); 304 ITerrainChannel hm = whichScene.Heightmap;
229 tc = Environment.TickCount; 305 tc = Environment.TickCount;
230 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); 306 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
231 EntityBase[] objs = whichScene.GetEntities(); 307 EntityBase[] objs = whichScene.GetEntities();
232 Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
233 //SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>();
234 List<float> z_sortheights = new List<float>(); 308 List<float> z_sortheights = new List<float>();
235 List<uint> z_localIDs = new List<uint>(); 309 List<uint> z_localIDs = new List<uint>();
310 Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
236 311
237 lock (objs) 312 try
238 { 313 {
239 foreach (EntityBase obj in objs) 314 lock (objs)
240 { 315 {
241 // Only draw the contents of SceneObjectGroup 316 foreach (EntityBase obj in objs)
242 if (obj is SceneObjectGroup)
243 { 317 {
244 SceneObjectGroup mapdot = (SceneObjectGroup)obj; 318 // Only draw the contents of SceneObjectGroup
245 Color mapdotspot = Color.Gray; // Default color when prim color is white 319 if (obj is SceneObjectGroup)
246
247 // Loop over prim in group
248 foreach (SceneObjectPart part in mapdot.Parts)
249 { 320 {
250 if (part == null) 321 SceneObjectGroup mapdot = (SceneObjectGroup)obj;
251 continue; 322 Color mapdotspot = Color.Gray; // Default color when prim color is white
252 323 // Loop over prim in group
253 // Draw if the object is at least 1 meter wide in any direction 324 foreach (SceneObjectPart part in mapdot.Parts)
254 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
255 { 325 {
256 // Try to get the RGBA of the default texture entry.. 326 if (part == null)
257 // 327 continue;
258 try 328
329 // Draw if the object is at least 1 meter wide in any direction
330 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
259 { 331 {
260 // get the null checks out of the way 332 // Try to get the RGBA of the default texture entry..
261 // skip the ones that break 333 //
262 if (part == null) 334 try
263 continue; 335 {
336 // get the null checks out of the way
337 // skip the ones that break
338 if (part == null)
339 continue;
264 340
265 if (part.Shape == null) 341 if (part.Shape == null)
266 continue; 342 continue;
267 343
268 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass) 344 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
269 continue; // eliminates trees from this since we don't really have a good tree representation 345 continue; // eliminates trees from this since we don't really have a good tree representation
270 // if you want tree blocks on the map comment the above line and uncomment the below line 346 // if you want tree blocks on the map comment the above line and uncomment the below line
271 //mapdotspot = Color.PaleGreen; 347 //mapdotspot = Color.PaleGreen;
272 348
273 Primitive.TextureEntry textureEntry = part.Shape.Textures; 349 Primitive.TextureEntry textureEntry = part.Shape.Textures;
274 350
275 if (textureEntry == null || textureEntry.DefaultTexture == null) 351 if (textureEntry == null || textureEntry.DefaultTexture == null)
276 continue; 352 continue;
277 353
278 Color4 texcolor = textureEntry.DefaultTexture.RGBA; 354 Color4 texcolor = textureEntry.DefaultTexture.RGBA;
279 355
280 // Not sure why some of these are null, oh well. 356 // Not sure why some of these are null, oh well.
281 357
282 int colorr = 255 - (int)(texcolor.R * 255f); 358 int colorr = 255 - (int)(texcolor.R * 255f);
283 int colorg = 255 - (int)(texcolor.G * 255f); 359 int colorg = 255 - (int)(texcolor.G * 255f);
284 int colorb = 255 - (int)(texcolor.B * 255f); 360 int colorb = 255 - (int)(texcolor.B * 255f);
285 361
286 if (!(colorr == 255 && colorg == 255 && colorb == 255)) 362 if (!(colorr == 255 && colorg == 255 && colorb == 255))
287 {
288 //Try to set the map spot color
289 try
290 {
291 // If the color gets goofy somehow, skip it *shakes fist at Color4
292 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
293 }
294 catch (ArgumentException)
295 { 363 {
364 //Try to set the map spot color
365 try
366 {
367 // If the color gets goofy somehow, skip it *shakes fist at Color4
368 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
369 }
370 catch (ArgumentException)
371 {
372 }
296 } 373 }
297 } 374 }
298 } 375 catch (IndexOutOfRangeException)
299 catch (IndexOutOfRangeException) 376 {
300 { 377 // Windows Array
301 // Windows Array 378 }
302 } 379 catch (ArgumentOutOfRangeException)
303 catch (ArgumentOutOfRangeException) 380 {
304 { 381 // Mono Array
305 // Mono Array 382 }
306 }
307
308 Vector3 pos = part.GetWorldPosition();
309
310 // skip prim outside of retion
311 if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
312 continue;
313
314 // skip prim in non-finite position
315 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
316 Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
317 continue;
318
319 // Figure out if object is under 256m above the height of the terrain
320 bool isBelow256AboveTerrain = false;
321 383
322 try 384 Vector3 pos = part.GetWorldPosition();
323 {
324 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
325 }
326 catch (Exception)
327 {
328 }
329 385
330 if (isBelow256AboveTerrain) 386 // skip prim outside of retion
331 { 387 if (!m_scene.PositionIsInCurrentRegion(pos))
332 // Translate scale by rotation so scale is represented properly when object is rotated
333 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
334 Vector3 scale = new Vector3();
335 Vector3 tScale = new Vector3();
336 Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
337
338 Quaternion llrot = part.GetWorldRotation();
339 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
340 scale = lscale * rot;
341
342 // negative scales don't work in this situation
343 scale.X = Math.Abs(scale.X);
344 scale.Y = Math.Abs(scale.Y);
345 scale.Z = Math.Abs(scale.Z);
346
347 // This scaling isn't very accurate and doesn't take into account the face rotation :P
348 int mapdrawstartX = (int)(pos.X - scale.X);
349 int mapdrawstartY = (int)(pos.Y - scale.Y);
350 int mapdrawendX = (int)(pos.X + scale.X);
351 int mapdrawendY = (int)(pos.Y + scale.Y);
352
353 // If object is beyond the edge of the map, don't draw it to avoid errors
354 if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1)
355 || mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0
356 || mapdrawendY > ((int)Constants.RegionSize - 1))
357 continue; 388 continue;
358 389
359#region obb face reconstruction part duex 390 // skip prim in non-finite position
360 Vector3[] vertexes = new Vector3[8]; 391 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
361 392 Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
362 // float[] distance = new float[6]; 393 continue;
363 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
364 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
365 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
366 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
367
368 tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
369 scale = ((tScale * rot));
370 vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
371 // vertexes[0].x = pos.X + vertexes[0].x;
372 //vertexes[0].y = pos.Y + vertexes[0].y;
373 //vertexes[0].z = pos.Z + vertexes[0].z;
374
375 FaceA[0] = vertexes[0];
376 FaceB[3] = vertexes[0];
377 FaceA[4] = vertexes[0];
378
379 tScale = lscale;
380 scale = ((tScale * rot));
381 vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
382
383 // vertexes[1].x = pos.X + vertexes[1].x;
384 // vertexes[1].y = pos.Y + vertexes[1].y;
385 //vertexes[1].z = pos.Z + vertexes[1].z;
386
387 FaceB[0] = vertexes[1];
388 FaceA[1] = vertexes[1];
389 FaceC[4] = vertexes[1];
390
391 tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
392 scale = ((tScale * rot));
393
394 vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
395
396 //vertexes[2].x = pos.X + vertexes[2].x;
397 //vertexes[2].y = pos.Y + vertexes[2].y;
398 //vertexes[2].z = pos.Z + vertexes[2].z;
399
400 FaceC[0] = vertexes[2];
401 FaceD[3] = vertexes[2];
402 FaceC[5] = vertexes[2];
403
404 tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
405 scale = ((tScale * rot));
406 vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
407
408 //vertexes[3].x = pos.X + vertexes[3].x;
409 // vertexes[3].y = pos.Y + vertexes[3].y;
410 // vertexes[3].z = pos.Z + vertexes[3].z;
411
412 FaceD[0] = vertexes[3];
413 FaceC[1] = vertexes[3];
414 FaceA[5] = vertexes[3];
415
416 tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
417 scale = ((tScale * rot));
418 vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
419
420 // vertexes[4].x = pos.X + vertexes[4].x;
421 // vertexes[4].y = pos.Y + vertexes[4].y;
422 // vertexes[4].z = pos.Z + vertexes[4].z;
423
424 FaceB[1] = vertexes[4];
425 FaceA[2] = vertexes[4];
426 FaceD[4] = vertexes[4];
427
428 tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
429 scale = ((tScale * rot));
430 vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
431
432 // vertexes[5].x = pos.X + vertexes[5].x;
433 // vertexes[5].y = pos.Y + vertexes[5].y;
434 // vertexes[5].z = pos.Z + vertexes[5].z;
435
436 FaceD[1] = vertexes[5];
437 FaceC[2] = vertexes[5];
438 FaceB[5] = vertexes[5];
439
440 tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
441 scale = ((tScale * rot));
442 vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
443 394
444 // vertexes[6].x = pos.X + vertexes[6].x; 395 // Figure out if object is under 256m above the height of the terrain
445 // vertexes[6].y = pos.Y + vertexes[6].y; 396 bool isBelow256AboveTerrain = false;
446 // vertexes[6].z = pos.Z + vertexes[6].z;
447 397
448 FaceB[2] = vertexes[6]; 398 try
449 FaceA[3] = vertexes[6]; 399 {
450 FaceB[4] = vertexes[6]; 400 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
401 }
402 catch (Exception)
403 {
404 }
451 405
452 tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z); 406 if (isBelow256AboveTerrain)
453 scale = ((tScale * rot)); 407 {
454 vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); 408 // Translate scale by rotation so scale is represented properly when object is rotated
409 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
410 Vector3 scale = new Vector3();
411 Vector3 tScale = new Vector3();
412 Vector3 axPos = new Vector3(pos.X, pos.Y, pos.Z);
413
414 Quaternion llrot = part.GetWorldRotation();
415 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
416 scale = lscale * rot;
417
418 // negative scales don't work in this situation
419 scale.X = Math.Abs(scale.X);
420 scale.Y = Math.Abs(scale.Y);
421 scale.Z = Math.Abs(scale.Z);
422
423 // This scaling isn't very accurate and doesn't take into account the face rotation :P
424 int mapdrawstartX = (int)(pos.X - scale.X);
425 int mapdrawstartY = (int)(pos.Y - scale.Y);
426 int mapdrawendX = (int)(pos.X + scale.X);
427 int mapdrawendY = (int)(pos.Y + scale.Y);
428
429 // If object is beyond the edge of the map, don't draw it to avoid errors
430 if (mapdrawstartX < 0
431 || mapdrawstartX > (hm.Width - 1)
432 || mapdrawendX < 0
433 || mapdrawendX > (hm.Width - 1)
434 || mapdrawstartY < 0
435 || mapdrawstartY > (hm.Height - 1)
436 || mapdrawendY < 0
437 || mapdrawendY > (hm.Height - 1))
438 continue;
439
440 #region obb face reconstruction part duex
441 Vector3[] vertexes = new Vector3[8];
442
443 // float[] distance = new float[6];
444 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
445 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
446 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
447 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
448
449 tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
450 scale = ((tScale * rot));
451 vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
452 // vertexes[0].x = pos.X + vertexes[0].x;
453 //vertexes[0].y = pos.Y + vertexes[0].y;
454 //vertexes[0].z = pos.Z + vertexes[0].z;
455
456 FaceA[0] = vertexes[0];
457 FaceB[3] = vertexes[0];
458 FaceA[4] = vertexes[0];
459
460 tScale = lscale;
461 scale = ((tScale * rot));
462 vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
463
464 // vertexes[1].x = pos.X + vertexes[1].x;
465 // vertexes[1].y = pos.Y + vertexes[1].y;
466 //vertexes[1].z = pos.Z + vertexes[1].z;
467
468 FaceB[0] = vertexes[1];
469 FaceA[1] = vertexes[1];
470 FaceC[4] = vertexes[1];
471
472 tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
473 scale = ((tScale * rot));
474
475 vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
476
477 //vertexes[2].x = pos.X + vertexes[2].x;
478 //vertexes[2].y = pos.Y + vertexes[2].y;
479 //vertexes[2].z = pos.Z + vertexes[2].z;
480
481 FaceC[0] = vertexes[2];
482 FaceD[3] = vertexes[2];
483 FaceC[5] = vertexes[2];
484
485 tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
486 scale = ((tScale * rot));
487 vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
488
489 //vertexes[3].x = pos.X + vertexes[3].x;
490 // vertexes[3].y = pos.Y + vertexes[3].y;
491 // vertexes[3].z = pos.Z + vertexes[3].z;
492
493 FaceD[0] = vertexes[3];
494 FaceC[1] = vertexes[3];
495 FaceA[5] = vertexes[3];
496
497 tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
498 scale = ((tScale * rot));
499 vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
500
501 // vertexes[4].x = pos.X + vertexes[4].x;
502 // vertexes[4].y = pos.Y + vertexes[4].y;
503 // vertexes[4].z = pos.Z + vertexes[4].z;
504
505 FaceB[1] = vertexes[4];
506 FaceA[2] = vertexes[4];
507 FaceD[4] = vertexes[4];
508
509 tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
510 scale = ((tScale * rot));
511 vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
512
513 // vertexes[5].x = pos.X + vertexes[5].x;
514 // vertexes[5].y = pos.Y + vertexes[5].y;
515 // vertexes[5].z = pos.Z + vertexes[5].z;
516
517 FaceD[1] = vertexes[5];
518 FaceC[2] = vertexes[5];
519 FaceB[5] = vertexes[5];
520
521 tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
522 scale = ((tScale * rot));
523 vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
524
525 // vertexes[6].x = pos.X + vertexes[6].x;
526 // vertexes[6].y = pos.Y + vertexes[6].y;
527 // vertexes[6].z = pos.Z + vertexes[6].z;
528
529 FaceB[2] = vertexes[6];
530 FaceA[3] = vertexes[6];
531 FaceB[4] = vertexes[6];
532
533 tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
534 scale = ((tScale * rot));
535 vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
455 536
456 // vertexes[7].x = pos.X + vertexes[7].x; 537 // vertexes[7].x = pos.X + vertexes[7].x;
457 // vertexes[7].y = pos.Y + vertexes[7].y; 538 // vertexes[7].y = pos.Y + vertexes[7].y;
458 // vertexes[7].z = pos.Z + vertexes[7].z; 539 // vertexes[7].z = pos.Z + vertexes[7].z;
459 540
460 FaceD[2] = vertexes[7]; 541 FaceD[2] = vertexes[7];
461 FaceC[3] = vertexes[7]; 542 FaceC[3] = vertexes[7];
462 FaceD[5] = vertexes[7]; 543 FaceD[5] = vertexes[7];
463#endregion 544 #endregion
464 545
465 //int wy = 0; 546 //int wy = 0;
466 547
467 //bool breakYN = false; // If we run into an error drawing, break out of the 548 //bool breakYN = false; // If we run into an error drawing, break out of the
468 // loop so we don't lag to death on error handling 549 // loop so we don't lag to death on error handling
469 DrawStruct ds = new DrawStruct(); 550 DrawStruct ds = new DrawStruct();
470 ds.brush = new SolidBrush(mapdotspot); 551 ds.brush = new SolidBrush(mapdotspot);
471 //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY); 552 //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
472 553
473 ds.trns = new face[FaceA.Length]; 554 ds.trns = new face[FaceA.Length];
474 555
475 for (int i = 0; i < FaceA.Length; i++) 556 for (int i = 0; i < FaceA.Length; i++)
476 { 557 {
477 Point[] working = new Point[5]; 558 Point[] working = new Point[5];
478 working[0] = project(FaceA[i], axPos); 559 working[0] = project(hm, FaceA[i], axPos);
479 working[1] = project(FaceB[i], axPos); 560 working[1] = project(hm, FaceB[i], axPos);
480 working[2] = project(FaceD[i], axPos); 561 working[2] = project(hm, FaceD[i], axPos);
481 working[3] = project(FaceC[i], axPos); 562 working[3] = project(hm, FaceC[i], axPos);
482 working[4] = project(FaceA[i], axPos); 563 working[4] = project(hm, FaceA[i], axPos);
483 564
484 face workingface = new face(); 565 face workingface = new face();
485 workingface.pts = working; 566 workingface.pts = working;
486 567
487 ds.trns[i] = workingface; 568 ds.trns[i] = workingface;
488 } 569 }
489 570
490 z_sort.Add(part.LocalId, ds); 571 z_sort.Add(part.LocalId, ds);
491 z_localIDs.Add(part.LocalId); 572 z_localIDs.Add(part.LocalId);
492 z_sortheights.Add(pos.Z); 573 z_sortheights.Add(pos.Z);
493 574
494 //for (int wx = mapdrawstartX; wx < mapdrawendX; wx++) 575 // for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
495 //{ 576 // {
496 //for (wy = mapdrawstartY; wy < mapdrawendY; wy++) 577 // for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
497 //{ 578 // {
498 //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy); 579 // m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
499 //try 580 // try
500 //{ 581 // {
501 // Remember, flip the y! 582 // // Remember, flip the y!
502 // mapbmp.SetPixel(wx, (255 - wy), mapdotspot); 583 // mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
503 //} 584 // }
504 //catch (ArgumentException) 585 // catch (ArgumentException)
505 //{ 586 // {
506 // breakYN = true; 587 // breakYN = true;
507 //} 588 // }
508 589 // }
509 //if (breakYN) 590 // if (breakYN)
510 // break; 591 // break;
592 // }
593 // }
511 //} 594 //}
595 } // Object is within 256m Z of terrain
596 } // object is at least a meter wide
597 } // loop over group children
598 } // entitybase is sceneobject group
599 } // foreach loop over entities
512 600
513 //if (breakYN) 601 float[] sortedZHeights = z_sortheights.ToArray();
514 // break; 602 uint[] sortedlocalIds = z_localIDs.ToArray();
515 //}
516 } // Object is within 256m Z of terrain
517 } // object is at least a meter wide
518 } // loop over group children
519 } // entitybase is sceneobject group
520 } // foreach loop over entities
521 603
522 float[] sortedZHeights = z_sortheights.ToArray(); 604 // Sort prim by Z position
523 uint[] sortedlocalIds = z_localIDs.ToArray(); 605 Array.Sort(sortedZHeights, sortedlocalIds);
524 606
525 // Sort prim by Z position 607 using (Graphics g = Graphics.FromImage(mapbmp))
526 Array.Sort(sortedZHeights, sortedlocalIds);
527
528 Graphics g = Graphics.FromImage(mapbmp);
529
530 for (int s = 0; s < sortedZHeights.Length; s++)
531 {
532 if (z_sort.ContainsKey(sortedlocalIds[s]))
533 { 608 {
534 DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]]; 609 for (int s = 0; s < sortedZHeights.Length; s++)
535 for (int r = 0; r < rectDrawStruct.trns.Length; r++)
536 { 610 {
537 g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts); 611 if (z_sort.ContainsKey(sortedlocalIds[s]))
612 {
613 DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]];
614 for (int r = 0; r < rectDrawStruct.trns.Length; r++)
615 {
616 g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts);
617 }
618 //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
619 }
538 } 620 }
539 //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
540 } 621 }
541 } 622 } // lock entities objs
542 623
543 g.Dispose(); 624 }
544 } // lock entities objs 625 finally
626 {
627 foreach (DrawStruct ds in z_sort.Values)
628 ds.brush.Dispose();
629 }
545 630
546 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms"); 631 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms");
632
547 return mapbmp; 633 return mapbmp;
548 } 634 }
549 635
550 private Point project(Vector3 point3d, Vector3 originpos) 636 private Point project(ITerrainChannel hm, Vector3 point3d, Vector3 originpos)
551 { 637 {
552 Point returnpt = new Point(); 638 Point returnpt = new Point();
553 //originpos = point3d; 639 //originpos = point3d;
554 //int d = (int)(256f / 1.5f); 640 //int d = (int)(256f / 1.5f);
555 641
556 //Vector3 topos = new Vector3(0, 0, 0); 642 //Vector3 topos = new Vector3(0, 0, 0);
557 // float z = -point3d.z - topos.z; 643 // float z = -point3d.z - topos.z;
558 644
559 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); 645 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d);
560 returnpt.Y = (int)(((int)Constants.RegionSize - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); 646 returnpt.Y = (int)((hm.Width - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d)));
561 647
562 return returnpt; 648 return returnpt;
563 } 649 }
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
index 992bff3..708286c 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
@@ -31,6 +31,7 @@ using System.Reflection;
31using log4net; 31using log4net;
32using Nini.Config; 32using Nini.Config;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
35 36
36namespace OpenSim.Region.CoreModules.World.LegacyMap 37namespace OpenSim.Region.CoreModules.World.LegacyMap
@@ -39,8 +40,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
39 { 40 {
40 private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); 41 private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95);
41 42
42 private static readonly ILog m_log = 43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]";
44 45
45 private Scene m_scene; 46 private Scene m_scene;
46 //private IConfigSource m_config; // not used currently 47 //private IConfigSource m_config; // not used currently
@@ -53,19 +54,26 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
53 54
54 public void TerrainToBitmap(Bitmap mapbmp) 55 public void TerrainToBitmap(Bitmap mapbmp)
55 { 56 {
57 m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
56 int tc = Environment.TickCount; 58 int tc = Environment.TickCount;
57 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain");
58 59
59 double[,] hm = m_scene.Heightmap.GetDoubles(); 60 ITerrainChannel hm = m_scene.Heightmap;
61
62 if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height)
63 {
64 m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>",
65 LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height);
66 }
67
60 bool ShadowDebugContinue = true; 68 bool ShadowDebugContinue = true;
61 69
62 bool terraincorruptedwarningsaid = false; 70 bool terraincorruptedwarningsaid = false;
63 71
64 float low = 255; 72 float low = 255;
65 float high = 0; 73 float high = 0;
66 for (int x = 0; x < (int)Constants.RegionSize; x++) 74 for (int x = 0; x < hm.Width; x++)
67 { 75 {
68 for (int y = 0; y < (int)Constants.RegionSize; y++) 76 for (int y = 0; y < hm.Height; y++)
69 { 77 {
70 float hmval = (float)hm[x, y]; 78 float hmval = (float)hm[x, y];
71 if (hmval < low) 79 if (hmval < low)
@@ -77,12 +85,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
77 85
78 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; 86 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
79 87
80 for (int x = 0; x < (int)Constants.RegionSize; x++) 88 for (int x = 0; x < hm.Width; x++)
81 { 89 {
82 for (int y = 0; y < (int)Constants.RegionSize; y++) 90 for (int y = 0; y < hm.Height; y++)
83 { 91 {
84 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left 92 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
85 int yr = ((int)Constants.RegionSize - 1) - y; 93 int yr = ((int)hm.Height - 1) - y;
86 94
87 float heightvalue = (float)hm[x, y]; 95 float heightvalue = (float)hm[x, y];
88 96
@@ -109,12 +117,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
109 // . 117 // .
110 // 118 //
111 // Shade the terrain for shadows 119 // Shade the terrain for shadows
112 if (x < ((int)Constants.RegionSize - 1) && yr < ((int)Constants.RegionSize - 1)) 120 if (x < (hm.Width - 1) && yr < (hm.Height - 1))
113 { 121 {
114 float hfvalue = (float)hm[x, y]; 122 float hfvalue = (float)hm[x, y];
115 float hfvaluecompare = 0f; 123 float hfvaluecompare = 0f;
116 124
117 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) 125 if ((x + 1 < hm.Width) && (y + 1 < hm.Height))
118 { 126 {
119 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there 127 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there
120 } 128 }
@@ -179,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
179 187
180 if (ShadowDebugContinue) 188 if (ShadowDebugContinue)
181 { 189 {
182 if ((x - 1 > 0) && (yr + 1 < (int)Constants.RegionSize)) 190 if ((x - 1 > 0) && (yr + 1 < hm.Height))
183 { 191 {
184 color = mapbmp.GetPixel(x - 1, yr + 1); 192 color = mapbmp.GetPixel(x - 1, yr + 1);
185 int r = color.R; 193 int r = color.R;
@@ -199,7 +207,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
199 { 207 {
200 if (!terraincorruptedwarningsaid) 208 if (!terraincorruptedwarningsaid)
201 { 209 {
202 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); 210 m_log.WarnFormat("[SHADED MAP TILE RENDERER]: 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);
203 terraincorruptedwarningsaid = true; 211 terraincorruptedwarningsaid = true;
204 } 212 }
205 color = Color.Black; 213 color = Color.Black;
@@ -229,16 +237,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
229 { 237 {
230 if (!terraincorruptedwarningsaid) 238 if (!terraincorruptedwarningsaid)
231 { 239 {
232 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); 240 m_log.WarnFormat("[SHADED MAP TILE RENDERER]: 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);
233 terraincorruptedwarningsaid = true; 241 terraincorruptedwarningsaid = true;
234 } 242 }
235 Color black = Color.Black; 243 Color black = Color.Black;
236 mapbmp.SetPixel(x, ((int)Constants.RegionSize - y) - 1, black); 244 mapbmp.SetPixel(x, (hm.Width - y) - 1, black);
237 } 245 }
238 } 246 }
239 } 247 }
240 } 248 }
241 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); 249
250 m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
242 } 251 }
243 } 252 }
244} 253}
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
index d13c2ef..9f23141 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
@@ -34,6 +34,8 @@ using Nini.Config;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenMetaverse.Imaging; 35using OpenMetaverse.Imaging;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
38 40
39namespace OpenSim.Region.CoreModules.World.LegacyMap 41namespace OpenSim.Region.CoreModules.World.LegacyMap
@@ -122,8 +124,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
122 { 124 {
123 #region Constants 125 #region Constants
124 126
125 private static readonly ILog m_log = 127 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
126 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 128 private static readonly string LogHeader = "[TEXTURED MAPTILE RENDERER]";
127 129
128 // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank"). 130 // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank").
129 // The color-values were choosen because they "look right" (at least to me) ;-) 131 // The color-values were choosen because they "look right" (at least to me) ;-)
@@ -173,7 +175,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
173 private Bitmap fetchTexture(UUID id) 175 private Bitmap fetchTexture(UUID id)
174 { 176 {
175 AssetBase asset = m_scene.AssetService.Get(id.ToString()); 177 AssetBase asset = m_scene.AssetService.Get(id.ToString());
176 m_log.DebugFormat("[TexturedMapTileRenderer]: Fetched texture {0}, found: {1}", id, asset != null); 178 m_log.DebugFormat("{0} Fetched texture {1}, found: {2}", LogHeader, id, asset != null);
177 if (asset == null) return null; 179 if (asset == null) return null;
178 180
179 ManagedImage managedImage; 181 ManagedImage managedImage;
@@ -188,18 +190,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
188 } 190 }
189 catch (DllNotFoundException) 191 catch (DllNotFoundException)
190 { 192 {
191 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id); 193 m_log.ErrorFormat("{0} OpenJpeg is not installed correctly on this system. Asset Data is empty for {1}", LogHeader, id);
192
193 } 194 }
194 catch (IndexOutOfRangeException) 195 catch (IndexOutOfRangeException)
195 { 196 {
196 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); 197 m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id);
197
198 } 198 }
199 catch (Exception) 199 catch (Exception)
200 { 200 {
201 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); 201 m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id);
202
203 } 202 }
204 return null; 203 return null;
205 204
@@ -233,10 +232,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
233 if (textureID == UUID.Zero) return defaultColor; // not set 232 if (textureID == UUID.Zero) return defaultColor; // not set
234 if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures 233 if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures
235 234
236 Bitmap bmp = fetchTexture(textureID); 235 Color color;
237 Color color = bmp == null ? defaultColor : computeAverageColor(bmp); 236
238 // store it for future reference 237 using (Bitmap bmp = fetchTexture(textureID))
239 m_mapping[textureID] = color; 238 {
239 color = bmp == null ? defaultColor : computeAverageColor(bmp);
240 // store it for future reference
241 m_mapping[textureID] = color;
242 }
240 243
241 return color; 244 return color;
242 } 245 }
@@ -267,8 +270,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
267 270
268 // the heigthfield might have some jumps in values. Rendered land is smooth, though, 271 // the heigthfield might have some jumps in values. Rendered land is smooth, though,
269 // as a slope is rendered at that place. So average 4 neighbour values to emulate that. 272 // as a slope is rendered at that place. So average 4 neighbour values to emulate that.
270 private float getHeight(double[,] hm, int x, int y) { 273 private float getHeight(ITerrainChannel hm, int x, int y) {
271 if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) 274 if (x < (hm.Width - 1) && y < (hm.Height - 1))
272 return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112); 275 return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112);
273 else 276 else
274 return (float)hm[x, y]; 277 return (float)hm[x, y];
@@ -278,7 +281,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
278 public void TerrainToBitmap(Bitmap mapbmp) 281 public void TerrainToBitmap(Bitmap mapbmp)
279 { 282 {
280 int tc = Environment.TickCount; 283 int tc = Environment.TickCount;
281 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); 284 m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
285
286 ITerrainChannel hm = m_scene.Heightmap;
287
288 if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height)
289 {
290 m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>",
291 LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height);
292 }
282 293
283 // These textures should be in the AssetCache anyway, as every client conneting to this 294 // These textures should be in the AssetCache anyway, as every client conneting to this
284 // region needs them. Except on start, when the map is recreated (before anyone connected), 295 // region needs them. Except on start, when the map is recreated (before anyone connected),
@@ -306,19 +317,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
306 317
307 float waterHeight = (float)settings.WaterHeight; 318 float waterHeight = (float)settings.WaterHeight;
308 319
309 double[,] hm = m_scene.Heightmap.GetDoubles(); 320 for (int x = 0; x < hm.Width; x++)
310
311 for (int x = 0; x < (int)Constants.RegionSize; x++)
312 { 321 {
313 float columnRatio = x / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation 322 float columnRatio = x / (hm.Width - 1); // 0 - 1, for interpolation
314 for (int y = 0; y < (int)Constants.RegionSize; y++) 323 for (int y = 0; y < hm.Height; y++)
315 { 324 {
316 float rowRatio = y / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation 325 float rowRatio = y / (hm.Height - 1); // 0 - 1, for interpolation
317 326
318 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left 327 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
319 int yr = ((int)Constants.RegionSize - 1) - y; 328 int yr = (hm.Height - 1) - y;
320 329
321 float heightvalue = getHeight(hm, x, y); 330 float heightvalue = getHeight(m_scene.Heightmap, x, y);
322 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) 331 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
323 heightvalue = 0; 332 heightvalue = 0;
324 333
@@ -368,9 +377,9 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
368 } 377 }
369 378
370 // Shade the terrain for shadows 379 // Shade the terrain for shadows
371 if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) 380 if (x < (hm.Width - 1) && y < (hm.Height - 1))
372 { 381 {
373 float hfvaluecompare = getHeight(hm, x + 1, y + 1); // light from north-east => look at land height there 382 float hfvaluecompare = getHeight(m_scene.Heightmap, x + 1, y + 1); // light from north-east => look at land height there
374 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare)) 383 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
375 hfvaluecompare = 0f; 384 hfvaluecompare = 0f;
376 385
@@ -412,7 +421,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
412 } 421 }
413 } 422 }
414 } 423 }
415 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); 424
425 m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
416 } 426 }
417 } 427 }
418} 428}
diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
index 4e20196..0a4e83e 100644
--- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
+++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
@@ -195,19 +195,20 @@ namespace OpenSim.Region.CoreModules.World.LightShare
195 if (m_scene.RegionInfo.WindlightSettings.valid) 195 if (m_scene.RegionInfo.WindlightSettings.valid)
196 { 196 {
197 List<byte[]> param = compileWindlightSettings(wl); 197 List<byte[]> param = compileWindlightSettings(wl);
198 client.SendGenericMessage("Windlight", param); 198 client.SendGenericMessage("Windlight", UUID.Random(), param);
199 } 199 }
200 else 200 else
201 { 201 {
202 List<byte[]> param = new List<byte[]>(); 202 List<byte[]> param = new List<byte[]>();
203 client.SendGenericMessage("WindlightReset", param); 203 client.SendGenericMessage("WindlightReset", UUID.Random(), param);
204 } 204 }
205 } 205 }
206 } 206 }
207 207
208 private void EventManager_OnMakeRootAgent(ScenePresence presence) 208 private void EventManager_OnMakeRootAgent(ScenePresence presence)
209 { 209 {
210 m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); 210// m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client {0}", presence.Name);
211
211 SendProfileToClient(presence.ControllingClient); 212 SendProfileToClient(presence.ControllingClient);
212 } 213 }
213 214
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
index 601e81e..46b0470 100644
--- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
+++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
@@ -595,6 +595,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap
595 /// <returns>true if the url matches an entry on the whitelist, false otherwise</returns> 595 /// <returns>true if the url matches an entry on the whitelist, false otherwise</returns>
596 protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist) 596 protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist)
597 { 597 {
598 if (whitelist == null)
599 return false;
600
598 Uri url = new Uri(rawUrl); 601 Uri url = new Uri(rawUrl);
599 602
600 foreach (string origWlUrl in whitelist) 603 foreach (string origWlUrl in whitelist)
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
index 03a96a4..ee57aed 100644
--- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
+++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
@@ -39,7 +39,6 @@ using OpenSim.Region.CoreModules.World.Media.Moap;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using OpenSim.Tests.Common; 41using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43 42
44namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests 43namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
45{ 44{
diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
index 1e4f0a4..2abc910 100644
--- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
@@ -38,6 +38,7 @@ using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Region.CoreModules.World.Objects.BuySell 43namespace OpenSim.Region.CoreModules.World.Objects.BuySell
43{ 44{
@@ -140,6 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
140 141
141 part.ObjectSaleType = 0; 142 part.ObjectSaleType = 0;
142 part.SalePrice = 10; 143 part.SalePrice = 10;
144 part.ClickAction = Convert.ToByte(0);
143 145
144 group.HasGroupChanged = true; 146 group.HasGroupChanged = true;
145 part.SendPropertiesToClient(remoteClient); 147 part.SendPropertiesToClient(remoteClient);
@@ -150,14 +152,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
150 break; 152 break;
151 153
152 case 2: // Sell a copy 154 case 2: // Sell a copy
153 Vector3 inventoryStoredPosition = new Vector3 155 Vector3 inventoryStoredPosition = new Vector3(
154 (((group.AbsolutePosition.X > (int)Constants.RegionSize) 156 Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6),
155 ? 250 157 Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6),
156 : group.AbsolutePosition.X)
157 ,
158 (group.AbsolutePosition.X > (int)Constants.RegionSize)
159 ? 250
160 : group.AbsolutePosition.X,
161 group.AbsolutePosition.Z); 158 group.AbsolutePosition.Z);
162 159
163 Vector3 originalPosition = group.AbsolutePosition; 160 Vector3 originalPosition = group.AbsolutePosition;
@@ -197,13 +194,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
197 item.InvType = (int)InventoryType.Object; 194 item.InvType = (int)InventoryType.Object;
198 item.Folder = categoryID; 195 item.Folder = categoryID;
199 196
200 uint nextPerms=(perms & 7) << 13; 197 PermissionsUtil.ApplyFoldedPermissions(perms, ref perms);
201 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
202 perms &= ~(uint)PermissionMask.Copy;
203 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
204 perms &= ~(uint)PermissionMask.Transfer;
205 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
206 perms &= ~(uint)PermissionMask.Modify;
207 198
208 item.BasePermissions = perms & part.NextOwnerMask; 199 item.BasePermissions = perms & part.NextOwnerMask;
209 item.CurrentPermissions = perms & part.NextOwnerMask; 200 item.CurrentPermissions = perms & part.NextOwnerMask;
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index 9fc2daf..e77f0aa 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -416,7 +416,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
416 416
417 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) 417 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
418 { 418 {
419 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); 419 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
420 return; 420 return;
421 } 421 }
422 422
@@ -425,7 +425,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
425 425
426 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) 426 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
427 { 427 {
428 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); 428 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
429 return; 429 return;
430 } 430 }
431 431
@@ -546,7 +546,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
546 { 546 {
547 ConsoleDisplayList cdl = new ConsoleDisplayList(); 547 ConsoleDisplayList cdl = new ConsoleDisplayList();
548 cdl.AddRow("Name", so.Name); 548 cdl.AddRow("Name", so.Name);
549 cdl.AddRow("Descrition", so.Description); 549 cdl.AddRow("Description", so.Description);
550 cdl.AddRow("Local ID", so.LocalId); 550 cdl.AddRow("Local ID", so.LocalId);
551 cdl.AddRow("UUID", so.UUID); 551 cdl.AddRow("UUID", so.UUID);
552 cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name)); 552 cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name));
@@ -597,6 +597,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
597 cdl.AddRow("LightFalloff", s.LightFalloff); 597 cdl.AddRow("LightFalloff", s.LightFalloff);
598 cdl.AddRow("LightIntensity", s.LightIntensity); 598 cdl.AddRow("LightIntensity", s.LightIntensity);
599 cdl.AddRow("LightRadius", s.LightRadius); 599 cdl.AddRow("LightRadius", s.LightRadius);
600 cdl.AddRow("Location (relative)", sop.RelativePosition);
600 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); 601 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
601 cdl.AddRow("PathBegin", s.PathBegin); 602 cdl.AddRow("PathBegin", s.PathBegin);
602 cdl.AddRow("PathEnd", s.PathEnd); 603 cdl.AddRow("PathEnd", s.PathEnd);
@@ -619,6 +620,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
619 cdl.AddRow("ProjectionFocus", s.ProjectionFocus); 620 cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
620 cdl.AddRow("ProjectionFOV", s.ProjectionFOV); 621 cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
621 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); 622 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
623 cdl.AddRow("Rotation (Relative)", sop.RotationOffset);
624 cdl.AddRow("Rotation (World)", sop.GetWorldRotation());
622 cdl.AddRow("Scale", s.Scale); 625 cdl.AddRow("Scale", s.Scale);
623 cdl.AddRow( 626 cdl.AddRow(
624 "SculptData", 627 "SculptData",
@@ -628,7 +631,22 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
628 cdl.AddRow("SculptType", s.SculptType); 631 cdl.AddRow("SculptType", s.SculptType);
629 cdl.AddRow("State", s.State); 632 cdl.AddRow("State", s.State);
630 633
631 // TODO, unpack and display texture entries 634 // TODO, need to display more information about textures but in a compact format
635 // to stop output becoming huge.
636 for (int i = 0; i < sop.GetNumberOfSides(); i++)
637 {
638 Primitive.TextureEntryFace teFace = s.Textures.FaceTextures[i];
639
640 UUID textureID;
641
642 if (teFace != null)
643 textureID = teFace.TextureID;
644 else
645 textureID = s.Textures.DefaultTexture.TextureID;
646
647 cdl.AddRow(string.Format("Face {0} texture ID", i), textureID);
648 }
649
632 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. 650 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
633 } 651 }
634 652
@@ -896,17 +914,17 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
896 914
897 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) 915 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
898 { 916 {
899 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); 917 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
900 endVector = Vector3.Zero; 918 endVector = Vector3.Zero;
901 919
902 return false; 920 return false;
903 } 921 }
904 922
905 string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single(); 923 string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single();
906 924
907 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) 925 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
908 { 926 {
909 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); 927 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
910 return false; 928 return false;
911 } 929 }
912 930
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index ddaa227..780ec69 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
30using System.Reflection; 31using System.Reflection;
31using log4net; 32using log4net;
32using Nini.Config; 33using Nini.Config;
@@ -38,6 +39,7 @@ using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces; 39using OpenSim.Services.Interfaces;
39 40
40using Mono.Addins; 41using Mono.Addins;
42using PermissionMask = OpenSim.Framework.PermissionMask;
41 43
42namespace OpenSim.Region.CoreModules.World.Permissions 44namespace OpenSim.Region.CoreModules.World.Permissions
43{ 45{
@@ -156,37 +158,44 @@ namespace OpenSim.Region.CoreModules.World.Permissions
156 158
157 public void Initialise(IConfigSource config) 159 public void Initialise(IConfigSource config)
158 { 160 {
159 IConfig myConfig = config.Configs["Startup"]; 161 string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules",
162 new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule");
160 163
161 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); 164 List<string> modules = new List<string>(permissionModules.Split(',').Select(m => m.Trim()));
162
163 List<string> modules = new List<string>(permissionModules.Split(','));
164 165
165 if (!modules.Contains("DefaultPermissionsModule")) 166 if (!modules.Contains("DefaultPermissionsModule"))
166 return; 167 return;
167 168
168 m_Enabled = true; 169 m_Enabled = true;
169 170
170 m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false); 171 m_allowGridGods = Util.GetConfigVarFromSections<bool>(config, "allow_grid_gods",
171 m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true); 172 new string[] { "Startup", "Permissions" }, false);
172 m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true); 173 m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(config, "serverside_object_permissions",
173 m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true); 174 new string[] { "Startup", "Permissions" }, true);
174 m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false); 175 m_propagatePermissions = Util.GetConfigVarFromSections<bool>(config, "propagate_permissions",
175 m_ParcelOwnerIsGod = myConfig.GetBoolean("parcel_owner_is_god", true); 176 new string[] { "Startup", "Permissions" }, true);
176 177 m_RegionOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_owner_is_god",
177 m_SimpleBuildPermissions = myConfig.GetBoolean("simple_build_permissions", false); 178 new string[] { "Startup", "Permissions" }, true);
179 m_RegionManagerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_manager_is_god",
180 new string[] { "Startup", "Permissions" }, false);
181 m_ParcelOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "parcel_owner_is_god",
182 new string[] { "Startup", "Permissions" }, true);
183
184 m_SimpleBuildPermissions = Util.GetConfigVarFromSections<bool>(config, "simple_build_permissions",
185 new string[] { "Startup", "Permissions" }, false);
178 186
179 m_allowedScriptCreators 187 m_allowedScriptCreators
180 = ParseUserSetConfigSetting(myConfig, "allowed_script_creators", m_allowedScriptCreators); 188 = ParseUserSetConfigSetting(config, "allowed_script_creators", m_allowedScriptCreators);
181 m_allowedScriptEditors 189 m_allowedScriptEditors
182 = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors); 190 = ParseUserSetConfigSetting(config, "allowed_script_editors", m_allowedScriptEditors);
183 191
184 if (m_bypassPermissions) 192 if (m_bypassPermissions)
185 m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); 193 m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks");
186 else 194 else
187 m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); 195 m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks");
188 196
189 string grant = myConfig.GetString("GrantLSL", ""); 197 string grant = Util.GetConfigVarFromSections<string>(config, "GrantLSL",
198 new string[] { "Startup", "Permissions" }, string.Empty);
190 if (grant.Length > 0) 199 if (grant.Length > 0)
191 { 200 {
192 foreach (string uuidl in grant.Split(',')) 201 foreach (string uuidl in grant.Split(','))
@@ -196,7 +205,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
196 } 205 }
197 } 206 }
198 207
199 grant = myConfig.GetString("GrantCS", ""); 208 grant = Util.GetConfigVarFromSections<string>(config, "GrantCS",
209 new string[] { "Startup", "Permissions" }, string.Empty);
200 if (grant.Length > 0) 210 if (grant.Length > 0)
201 { 211 {
202 foreach (string uuidl in grant.Split(',')) 212 foreach (string uuidl in grant.Split(','))
@@ -206,7 +216,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
206 } 216 }
207 } 217 }
208 218
209 grant = myConfig.GetString("GrantVB", ""); 219 grant = Util.GetConfigVarFromSections<string>(config, "GrantVB",
220 new string[] { "Startup", "Permissions" }, string.Empty);
210 if (grant.Length > 0) 221 if (grant.Length > 0)
211 { 222 {
212 foreach (string uuidl in grant.Split(',')) 223 foreach (string uuidl in grant.Split(','))
@@ -216,7 +227,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
216 } 227 }
217 } 228 }
218 229
219 grant = myConfig.GetString("GrantJS", ""); 230 grant = Util.GetConfigVarFromSections<string>(config, "GrantJS",
231 new string[] { "Startup", "Permissions" }, string.Empty);
220 if (grant.Length > 0) 232 if (grant.Length > 0)
221 { 233 {
222 foreach (string uuidl in grant.Split(',')) 234 foreach (string uuidl in grant.Split(','))
@@ -226,7 +238,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
226 } 238 }
227 } 239 }
228 240
229 grant = myConfig.GetString("GrantYP", ""); 241 grant = Util.GetConfigVarFromSections<string>(config, "GrantYP",
242 new string[] { "Startup", "Permissions" }, string.Empty);
230 if (grant.Length > 0) 243 if (grant.Length > 0)
231 { 244 {
232 foreach (string uuidl in grant.Split(',')) 245 foreach (string uuidl in grant.Split(','))
@@ -456,7 +469,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
456 469
457 return false; 470 return false;
458 } 471 }
459 472
460 /// <summary> 473 /// <summary>
461 /// Parse a user set configuration setting 474 /// Parse a user set configuration setting
462 /// </summary> 475 /// </summary>
@@ -464,11 +477,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions
464 /// <param name="settingName"></param> 477 /// <param name="settingName"></param>
465 /// <param name="defaultValue">The default value for this attribute</param> 478 /// <param name="defaultValue">The default value for this attribute</param>
466 /// <returns>The parsed value</returns> 479 /// <returns>The parsed value</returns>
467 private static UserSet ParseUserSetConfigSetting(IConfig config, string settingName, UserSet defaultValue) 480 private static UserSet ParseUserSetConfigSetting(IConfigSource config, string settingName, UserSet defaultValue)
468 { 481 {
469 UserSet userSet = defaultValue; 482 UserSet userSet = defaultValue;
470 483
471 string rawSetting = config.GetString(settingName, defaultValue.ToString()); 484 string rawSetting = Util.GetConfigVarFromSections<string>(config, settingName,
485 new string[] {"Startup", "Permissions"}, defaultValue.ToString());
472 486
473 // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term 487 // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term
474 // this should disappear. 488 // this should disappear.
@@ -787,8 +801,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
787 801
788 // Friends with benefits should be able to edit the objects too 802 // Friends with benefits should be able to edit the objects too
789 if (IsFriendWithPerms(currentUser, objectOwner)) 803 if (IsFriendWithPerms(currentUser, objectOwner))
804 {
790 // Return immediately, so that the administrator can share objects with friends 805 // Return immediately, so that the administrator can share objects with friends
791 return true; 806 return true;
807 }
792 808
793 // Users should be able to edit what is over their land. 809 // Users should be able to edit what is over their land.
794 ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y); 810 ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y);
@@ -887,7 +903,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
887 return permission; 903 return permission;
888 } 904 }
889 905
890 protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers) 906 protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers, bool allowEstateManager)
891 { 907 {
892 if (parcel.LandData.OwnerID == user) 908 if (parcel.LandData.OwnerID == user)
893 { 909 {
@@ -902,7 +918,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
902 return true; 918 return true;
903 } 919 }
904 920
905 if (IsEstateManager(user)) 921 if (allowEstateManager && IsEstateManager(user))
906 { 922 {
907 return true; 923 return true;
908 } 924 }
@@ -929,7 +945,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
929 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 945 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
930 if (m_bypassPermissions) return m_bypassPermissionsValue; 946 if (m_bypassPermissions) return m_bypassPermissionsValue;
931 947
932 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease); 948 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease, false);
933 } 949 }
934 950
935 private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene) 951 private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene)
@@ -937,7 +953,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
937 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 953 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
938 if (m_bypassPermissions) return m_bypassPermissionsValue; 954 if (m_bypassPermissions) return m_bypassPermissionsValue;
939 955
940 return GenericParcelOwnerPermission(user, parcel, 0); 956 return GenericParcelOwnerPermission(user, parcel, 0,true);
941 } 957 }
942 958
943 private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene) 959 private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene)
@@ -954,7 +970,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
954 if ((client.GetGroupPowers(parcel.LandData.GroupID) & (ulong)GroupPowers.LandDeed) == 0) 970 if ((client.GetGroupPowers(parcel.LandData.GroupID) & (ulong)GroupPowers.LandDeed) == 0)
955 return false; 971 return false;
956 972
957 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed); 973 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed, false);
958 } 974 }
959 975
960 private bool CanDeedObject(UUID user, UUID group, Scene scene) 976 private bool CanDeedObject(UUID user, UUID group, Scene scene)
@@ -995,9 +1011,11 @@ namespace OpenSim.Region.CoreModules.World.Permissions
995 return false; 1011 return false;
996 1012
997 if (part.OwnerID == owner) 1013 if (part.OwnerID == owner)
998 return ((part.OwnerMask & PERM_COPY) != 0); 1014 {
999 1015 if ((part.OwnerMask & PERM_COPY) == 0)
1000 if (part.GroupID != UUID.Zero) 1016 return false;
1017 }
1018 else if (part.GroupID != UUID.Zero)
1001 { 1019 {
1002 if ((part.OwnerID == part.GroupID) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0))) 1020 if ((part.OwnerID == part.GroupID) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0)))
1003 return false; 1021 return false;
@@ -1039,7 +1057,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1039 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 1057 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1040 if (m_bypassPermissions) return m_bypassPermissionsValue; 1058 if (m_bypassPermissions) return m_bypassPermissionsValue;
1041 1059
1042 return GenericParcelOwnerPermission(user, parcel, (ulong)p); 1060 return GenericParcelOwnerPermission(user, parcel, (ulong)p, false);
1043 } 1061 }
1044 1062
1045 /// <summary> 1063 /// <summary>
@@ -1438,27 +1456,33 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1438 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 1456 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1439 if (m_bypassPermissions) return m_bypassPermissionsValue; 1457 if (m_bypassPermissions) return m_bypassPermissionsValue;
1440 1458
1441 bool permission = false; 1459// m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name);
1442
1443 ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
1444 if (land == null) return false;
1445 1460
1446 if ((land.LandData.Flags & ((int)ParcelFlags.CreateObjects)) == 1461 ILandObject parcel = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
1447 (int)ParcelFlags.CreateObjects) 1462 if (parcel == null)
1448 permission = true; 1463 return false;
1449 1464
1450 if (IsAdministrator(owner)) 1465 if ((parcel.LandData.Flags & (uint)ParcelFlags.CreateObjects) != 0)
1451 { 1466 {
1452 permission = true; 1467 return true;
1453 } 1468 }
1454 1469 else if ((owner == parcel.LandData.OwnerID) || IsAdministrator(owner))
1455 // Powers are zero, because GroupPowers.AllowRez is not a precondition for rezzing objects
1456 if (GenericParcelPermission(owner, objectPosition, 0))
1457 { 1470 {
1458 permission = true; 1471 return true;
1472 }
1473 else if (((parcel.LandData.Flags & (uint)ParcelFlags.CreateGroupObjects) != 0)
1474 && (parcel.LandData.GroupID != UUID.Zero) && IsGroupMember(parcel.LandData.GroupID, owner, 0))
1475 {
1476 return true;
1477 }
1478 else if (parcel.LandData.GroupID != UUID.Zero && IsGroupMember(parcel.LandData.GroupID, owner, (ulong)GroupPowers.AllowRez))
1479 {
1480 return true;
1481 }
1482 else
1483 {
1484 return false;
1459 } 1485 }
1460
1461 return permission;
1462 } 1486 }
1463 1487
1464 private bool CanRunConsoleCommand(UUID user, Scene requestFromScene) 1488 private bool CanRunConsoleCommand(UUID user, Scene requestFromScene)
@@ -1483,7 +1507,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1483 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 1507 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1484 if (m_bypassPermissions) return m_bypassPermissionsValue; 1508 if (m_bypassPermissions) return m_bypassPermissionsValue;
1485 1509
1486 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale); 1510 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale, false);
1487 } 1511 }
1488 1512
1489 private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) 1513 private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene)
@@ -1500,6 +1524,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1500 if (m_bypassPermissions) return m_bypassPermissionsValue; 1524 if (m_bypassPermissions) return m_bypassPermissionsValue;
1501 1525
1502 bool permission = GenericObjectPermission(userID, objectID, false); 1526 bool permission = GenericObjectPermission(userID, objectID, false);
1527
1528 SceneObjectGroup so = (SceneObjectGroup)m_scene.Entities[objectID];
1529
1503 if (!permission) 1530 if (!permission)
1504 { 1531 {
1505 if (!m_scene.Entities.ContainsKey(objectID)) 1532 if (!m_scene.Entities.ContainsKey(objectID))
@@ -1513,31 +1540,23 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1513 return false; 1540 return false;
1514 } 1541 }
1515 1542
1516 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
1517 // UUID taskOwner = null; 1543 // UUID taskOwner = null;
1518 // Added this because at this point in time it wouldn't be wise for 1544 // Added this because at this point in time it wouldn't be wise for
1519 // the administrator object permissions to take effect. 1545 // the administrator object permissions to take effect.
1520 // UUID objectOwner = task.OwnerID; 1546 // UUID objectOwner = task.OwnerID;
1521 1547
1522 if ((task.RootPart.EveryoneMask & PERM_COPY) != 0) 1548 if ((so.RootPart.EveryoneMask & PERM_COPY) != 0)
1523 permission = true; 1549 permission = true;
1550 }
1524 1551
1525 if (task.OwnerID != userID) 1552 if (so.OwnerID != userID)
1526 { 1553 {
1527 if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS)) 1554 if ((so.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS))
1528 permission = false; 1555 permission = false;
1529 }
1530 else
1531 {
1532 if ((task.GetEffectivePermissions() & PERM_COPY) != PERM_COPY)
1533 permission = false;
1534 }
1535 } 1556 }
1536 else 1557 else
1537 { 1558 {
1538 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID]; 1559 if ((so.GetEffectivePermissions() & PERM_COPY) != PERM_COPY)
1539
1540 if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS))
1541 permission = false; 1560 permission = false;
1542 } 1561 }
1543 1562
@@ -1556,10 +1575,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1556 float X = position.X; 1575 float X = position.X;
1557 float Y = position.Y; 1576 float Y = position.Y;
1558 1577
1559 if (X > ((int)Constants.RegionSize - 1)) 1578 if (X > ((int)m_scene.RegionInfo.RegionSizeX - 1))
1560 X = ((int)Constants.RegionSize - 1); 1579 X = ((int)m_scene.RegionInfo.RegionSizeX - 1);
1561 if (Y > ((int)Constants.RegionSize - 1)) 1580 if (Y > ((int)m_scene.RegionInfo.RegionSizeY - 1))
1562 Y = ((int)Constants.RegionSize - 1); 1581 Y = ((int)m_scene.RegionInfo.RegionSizeY - 1);
1563 if (X < 0) 1582 if (X < 0)
1564 X = 0; 1583 X = 0;
1565 if (Y < 0) 1584 if (Y < 0)
diff --git a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
index 7d35473..bb4dcce 100644
--- a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
@@ -81,7 +81,32 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
81 m_console.Commands.AddCommand( 81 m_console.Commands.AddCommand(
82 "Regions", false, "show scene", 82 "Regions", false, "show scene",
83 "show scene", 83 "show scene",
84 "Show live scene information for the currently selected region.", HandleShowScene); 84 "Show live information for the currently selected scene (fps, prims, etc.).", HandleShowScene);
85
86 m_console.Commands.AddCommand(
87 "Regions", false, "show region",
88 "show region",
89 "Show control information for the currently selected region (host name, max physical prim size, etc).",
90 "A synonym for \"region get\"",
91 HandleShowRegion);
92
93 m_console.Commands.AddCommand(
94 "Regions", false, "region get",
95 "region get",
96 "Show control information for the currently selected region (host name, max physical prim size, etc).",
97 "Some parameters can be set with the \"region set\" command.\n"
98 + "Others must be changed via a viewer (usually via the region/estate dialog box).",
99 HandleShowRegion);
100
101 m_console.Commands.AddCommand(
102 "Regions", false, "region set",
103 "region set",
104 "Set control information for the currently selected region.",
105 "Currently, the following parameters can be set:\n"
106 + "agent-limit <int> - Current root agent limit. This is persisted over restart.\n"
107 + "max-agent-limit <int> - Maximum root agent limit. agent-limit cannot exceed this."
108 + " This is not persisted over restart - to set it every time you must add a MaxAgents entry to your regions file.",
109 HandleRegionSet);
85 } 110 }
86 111
87 public void RemoveRegion(Scene scene) 112 public void RemoveRegion(Scene scene)
@@ -94,6 +119,139 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
94// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 119// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
95 } 120 }
96 121
122 private void HandleShowRegion(string module, string[] cmd)
123 {
124 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
125 return;
126
127 RegionInfo ri = m_scene.RegionInfo;
128 RegionSettings rs = ri.RegionSettings;
129
130 StringBuilder sb = new StringBuilder();
131 sb.AppendFormat("Region information for {0}\n", m_scene.Name);
132
133 ConsoleDisplayList dispList = new ConsoleDisplayList();
134 dispList.AddRow("Region ID", ri.RegionID);
135 dispList.AddRow("Region handle", ri.RegionHandle);
136 dispList.AddRow("Region location", string.Format("{0},{1}", ri.RegionLocX, ri.RegionLocY));
137 dispList.AddRow("Region size", string.Format("{0}x{1}", ri.RegionSizeX, ri.RegionSizeY));
138 //dispList.AddRow("Region type", ri.RegionType);
139 dispList.AddRow("Maturity", rs.Maturity);
140 dispList.AddRow("Region address", ri.ServerURI);
141 dispList.AddRow("From region file", ri.RegionFile);
142 dispList.AddRow("External endpoint", ri.ExternalEndPoint);
143 dispList.AddRow("Internal endpoint", ri.InternalEndPoint);
144 dispList.AddRow("Access level", ri.AccessLevel);
145 dispList.AddRow("Agent limit", rs.AgentLimit);
146 dispList.AddRow("Max agent limit", ri.AgentCapacity);
147 dispList.AddRow("Linkset capacity", ri.LinksetCapacity <= 0 ? "not set" : ri.LinksetCapacity.ToString());
148 dispList.AddRow("Prim capacity", ri.ObjectCapacity);
149 dispList.AddRow("Prim bonus", rs.ObjectBonus);
150 dispList.AddRow("Max prims per user", ri.MaxPrimsPerUser < 0 ? "n/a" : ri.MaxPrimsPerUser.ToString());
151 dispList.AddRow("Clamp prim size", ri.ClampPrimSize);
152 dispList.AddRow("Non physical prim min size", ri.NonphysPrimMin <= 0 ? "not set" : string.Format("{0} m", ri.NonphysPrimMin));
153 dispList.AddRow("Non physical prim max size", ri.NonphysPrimMax <= 0 ? "not set" : string.Format("{0} m", ri.NonphysPrimMax));
154 dispList.AddRow("Physical prim min size", ri.PhysPrimMin <= 0 ? "not set" : string.Format("{0} m", ri.PhysPrimMin));
155 dispList.AddRow("Physical prim max size", ri.PhysPrimMax <= 0 ? "not set" : string.Format("{0} m", ri.PhysPrimMax));
156
157 dispList.AddRow("Allow Damage", rs.AllowDamage);
158 dispList.AddRow("Allow Land join/divide", rs.AllowLandJoinDivide);
159 dispList.AddRow("Allow land resell", rs.AllowLandResell);
160 dispList.AddRow("Block fly", rs.BlockFly);
161 dispList.AddRow("Block show in search", rs.BlockShowInSearch);
162 dispList.AddRow("Block terraform", rs.BlockTerraform);
163 dispList.AddRow("Covenant UUID", rs.Covenant);
164 dispList.AddRow("Convenant change Unix time", rs.CovenantChangedDateTime);
165 dispList.AddRow("Disable collisions", rs.DisableCollisions);
166 dispList.AddRow("Disable physics", rs.DisablePhysics);
167 dispList.AddRow("Disable scripts", rs.DisableScripts);
168 dispList.AddRow("Restrict pushing", rs.RestrictPushing);
169 dispList.AddRow("Fixed sun", rs.FixedSun);
170 dispList.AddRow("Sun position", rs.SunPosition);
171 dispList.AddRow("Sun vector", rs.SunVector);
172 dispList.AddRow("Use estate sun", rs.UseEstateSun);
173 dispList.AddRow("Telehub UUID", rs.TelehubObject);
174 dispList.AddRow("Terrain lower limit", string.Format("{0} m", rs.TerrainLowerLimit));
175 dispList.AddRow("Terrain raise limit", string.Format("{0} m", rs.TerrainRaiseLimit));
176 dispList.AddRow("Water height", string.Format("{0} m", rs.WaterHeight));
177
178 dispList.AddRow("Maptile static file", ri.MaptileStaticFile);
179 dispList.AddRow("Maptile static UUID", ri.MaptileStaticUUID);
180 dispList.AddRow("Last map refresh", ri.lastMapRefresh);
181 dispList.AddRow("Last map UUID", ri.lastMapUUID);
182
183 dispList.AddToStringBuilder(sb);
184
185 MainConsole.Instance.Output(sb.ToString());
186 }
187
188 private void HandleRegionSet(string module, string[] args)
189 {
190 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
191 return;
192
193 if (args.Length != 4)
194 {
195 MainConsole.Instance.OutputFormat("Usage: region set <param> <value>");
196 return;
197 }
198
199 string param = args[2];
200 string rawValue = args[3];
201
202 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
203 return;
204
205 RegionInfo ri = m_scene.RegionInfo;
206 RegionSettings rs = ri.RegionSettings;
207
208 if (param == "agent-limit")
209 {
210 int newValue;
211
212 if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, rawValue, out newValue))
213 return;
214
215 if (newValue > ri.AgentCapacity)
216 {
217 MainConsole.Instance.OutputFormat(
218 "Cannot set {0} to {1} in {2} as max-agent-limit is {3}", "agent-limit",
219 newValue, m_scene.Name, ri.AgentCapacity);
220 }
221 else
222 {
223 rs.AgentLimit = newValue;
224
225 MainConsole.Instance.OutputFormat(
226 "{0} set to {1} in {2}", "agent-limit", newValue, m_scene.Name);
227 }
228
229 rs.Save();
230 }
231 else if (param == "max-agent-limit")
232 {
233 int newValue;
234
235 if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, rawValue, out newValue))
236 return;
237
238 ri.AgentCapacity = newValue;
239
240 MainConsole.Instance.OutputFormat(
241 "{0} set to {1} in {2}", "max-agent-limit", newValue, m_scene.Name);
242
243 if (ri.AgentCapacity < rs.AgentLimit)
244 {
245 rs.AgentLimit = ri.AgentCapacity;
246
247 MainConsole.Instance.OutputFormat(
248 "Reducing {0} to {1} in {2}", "agent-limit", rs.AgentLimit, m_scene.Name);
249 }
250
251 rs.Save();
252 }
253 }
254
97 private void HandleShowScene(string module, string[] cmd) 255 private void HandleShowScene(string module, string[] cmd)
98 { 256 {
99 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) 257 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
index 249a40d..75a8295 100644
--- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
@@ -46,8 +46,8 @@ namespace OpenSim.Region.CoreModules.World.Region
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")] 46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")]
47 public class RestartModule : INonSharedRegionModule, IRestartModule 47 public class RestartModule : INonSharedRegionModule, IRestartModule
48 { 48 {
49// private static readonly ILog m_log = 49 private static readonly ILog m_log =
50// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 51
52 protected Scene m_Scene; 52 protected Scene m_Scene;
53 protected Timer m_CountdownTimer = null; 53 protected Timer m_CountdownTimer = null;
@@ -203,18 +203,30 @@ namespace OpenSim.Region.CoreModules.World.Region
203 203
204 public void SetTimer(int intervalSeconds) 204 public void SetTimer(int intervalSeconds)
205 { 205 {
206 m_CountdownTimer = new Timer(); 206 if (intervalSeconds > 0)
207 m_CountdownTimer.AutoReset = false; 207 {
208 m_CountdownTimer.Interval = intervalSeconds * 1000; 208 m_CountdownTimer = new Timer();
209 m_CountdownTimer.Elapsed += OnTimer; 209 m_CountdownTimer.AutoReset = false;
210 m_CountdownTimer.Start(); 210 m_CountdownTimer.Interval = intervalSeconds * 1000;
211 m_CountdownTimer.Elapsed += OnTimer;
212 m_CountdownTimer.Start();
213 }
214 else if (m_CountdownTimer != null)
215 {
216 m_CountdownTimer.Stop();
217 m_CountdownTimer = null;
218 }
219 else
220 {
221 m_log.WarnFormat(
222 "[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval",
223 intervalSeconds, m_Scene.Name);
224 }
211 } 225 }
212 226
213 private void OnTimer(object source, ElapsedEventArgs e) 227 private void OnTimer(object source, ElapsedEventArgs e)
214 { 228 {
215 int nextInterval = DoOneNotice(); 229 SetTimer(DoOneNotice());
216
217 SetTimer(nextInterval);
218 } 230 }
219 231
220 public void AbortRestart(string message) 232 public void AbortRestart(string message)
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
index 328fbf0..65f464a 100644
--- a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
+++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
@@ -54,13 +54,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser
54 { 54 {
55 string xmlstream = GetObjectXml(scene); 55 string xmlstream = GetObjectXml(scene);
56 56
57 MemoryStream stream = ReformatXmlString(xmlstream); 57 using (MemoryStream stream = ReformatXmlString(xmlstream))
58 58 {
59 stream.Seek(0, SeekOrigin.Begin); 59 stream.Seek(0, SeekOrigin.Begin);
60 CreateXmlFile(stream, fileName); 60 CreateXmlFile(stream, fileName);
61 61
62 stream.Seek(0, SeekOrigin.Begin); 62 stream.Seek(0, SeekOrigin.Begin);
63 CreateCompressedXmlFile(stream, fileName); 63 CreateCompressedXmlFile(stream, fileName);
64 }
64 } 65 }
65 66
66 private static MemoryStream ReformatXmlString(string xmlstream) 67 private static MemoryStream ReformatXmlString(string xmlstream)
@@ -112,13 +113,16 @@ namespace OpenSim.Region.CoreModules.World.Serialiser
112 { 113 {
113 #region GZip Compressed Version 114 #region GZip Compressed Version
114 115
115 FileStream objectsFileCompressed = new FileStream(fileName + ".gzs", FileMode.Create); 116 using (FileStream objectsFileCompressed = new FileStream(fileName + ".gzs", FileMode.Create))
116 MemoryStream gzipMSStream = new MemoryStream(); 117 using (MemoryStream gzipMSStream = new MemoryStream())
117 GZipStream gzipStream = new GZipStream(gzipMSStream, CompressionMode.Compress); 118 {
118 xmlStream.WriteTo(gzipStream); 119 using (GZipStream gzipStream = new GZipStream(gzipMSStream, CompressionMode.Compress, true))
119 gzipMSStream.WriteTo(objectsFileCompressed); 120 {
120 objectsFileCompressed.Flush(); 121 xmlStream.WriteTo(gzipStream);
121 objectsFileCompressed.Close(); 122 }
123
124 gzipMSStream.WriteTo(objectsFileCompressed);
125 }
122 126
123 #endregion 127 #endregion
124 } 128 }
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
index bcb8e2f..a5bb1a7 100644
--- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
+++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
@@ -27,6 +27,7 @@
27 27
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Text;
30using System.Xml; 31using System.Xml;
31using log4net.Config; 32using log4net.Config;
32using NUnit.Framework; 33using NUnit.Framework;
@@ -35,120 +36,358 @@ using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Scenes.Serialization; 37using OpenSim.Region.Framework.Scenes.Serialization;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
39using OpenMetaverse.StructuredData;
38 40
39namespace OpenSim.Region.CoreModules.World.Serialiser.Tests 41namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
40{ 42{
41 [TestFixture] 43 [TestFixture]
42 public class SerialiserTests : OpenSimTestCase 44 public class SerialiserTests : OpenSimTestCase
43 { 45 {
44 private string xml = @" 46 private const string ObjectRootPartStubXml =
45 <SceneObjectGroup> 47@"<SceneObjectGroup>
46 <RootPart> 48 <RootPart>
47 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 49 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
48 <AllowedDrop>false</AllowedDrop> 50 <AllowedDrop>false</AllowedDrop>
49 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID> 51 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID>
50 <FolderID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></FolderID> 52 <FolderID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></FolderID>
51 <InventorySerial>1</InventorySerial> 53 <InventorySerial>1</InventorySerial>
52 <TaskInventory /> 54 <TaskInventory />
53 <ObjectFlags>0</ObjectFlags> 55 <ObjectFlags>0</ObjectFlags>
54 <UUID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></UUID> 56 <UUID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></UUID>
55 <LocalId>2698615125</LocalId> 57 <LocalId>2698615125</LocalId>
56 <Name>PrimMyRide</Name> 58 <Name>PrimMyRide</Name>
57 <Material>0</Material> 59 <Material>0</Material>
58 <PassTouches>false</PassTouches> 60 <PassTouches>false</PassTouches>
59 <RegionHandle>1099511628032000</RegionHandle> 61 <RegionHandle>1099511628032000</RegionHandle>
60 <ScriptAccessPin>0</ScriptAccessPin> 62 <ScriptAccessPin>0</ScriptAccessPin>
61 <GroupPosition><X>147.23</X><Y>92.698</Y><Z>22.78084</Z></GroupPosition> 63 <GroupPosition><X>147.23</X><Y>92.698</Y><Z>22.78084</Z></GroupPosition>
62 <OffsetPosition><X>0</X><Y>0</Y><Z>0</Z></OffsetPosition> 64 <OffsetPosition><X>0</X><Y>0</Y><Z>0</Z></OffsetPosition>
63 <RotationOffset><X>-4.371139E-08</X><Y>-1</Y><Z>-4.371139E-08</Z><W>0</W></RotationOffset> 65 <RotationOffset><X>-4.371139E-08</X><Y>-1</Y><Z>-4.371139E-08</Z><W>0</W></RotationOffset>
64 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity> 66 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity>
65 <RotationalVelocity><X>0</X><Y>0</Y><Z>0</Z></RotationalVelocity> 67 <RotationalVelocity><X>0</X><Y>0</Y><Z>0</Z></RotationalVelocity>
66 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity> 68 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity>
67 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration> 69 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration>
68 <Description /> 70 <Description />
69 <Color /> 71 <Color />
70 <Text /> 72 <Text />
71 <SitName /> 73 <SitName />
72 <TouchName /> 74 <TouchName />
73 <LinkNum>0</LinkNum> 75 <LinkNum>0</LinkNum>
74 <ClickAction>0</ClickAction> 76 <ClickAction>0</ClickAction>
75 <Shape> 77 <Shape>
76 <ProfileCurve>1</ProfileCurve> 78 <ProfileCurve>1</ProfileCurve>
77 <TextureEntry>AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==</TextureEntry> 79 <TextureEntry>AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==</TextureEntry>
78 <ExtraParams>AA==</ExtraParams> 80 <ExtraParams>AA==</ExtraParams>
79 <PathBegin>0</PathBegin> 81 <PathBegin>0</PathBegin>
80 <PathCurve>16</PathCurve> 82 <PathCurve>16</PathCurve>
81 <PathEnd>0</PathEnd> 83 <PathEnd>0</PathEnd>
82 <PathRadiusOffset>0</PathRadiusOffset> 84 <PathRadiusOffset>0</PathRadiusOffset>
83 <PathRevolutions>0</PathRevolutions> 85 <PathRevolutions>0</PathRevolutions>
84 <PathScaleX>100</PathScaleX> 86 <PathScaleX>100</PathScaleX>
85 <PathScaleY>100</PathScaleY> 87 <PathScaleY>100</PathScaleY>
86 <PathShearX>0</PathShearX> 88 <PathShearX>0</PathShearX>
87 <PathShearY>0</PathShearY> 89 <PathShearY>0</PathShearY>
88 <PathSkew>0</PathSkew> 90 <PathSkew>0</PathSkew>
89 <PathTaperX>0</PathTaperX> 91 <PathTaperX>0</PathTaperX>
90 <PathTaperY>0</PathTaperY> 92 <PathTaperY>0</PathTaperY>
91 <PathTwist>0</PathTwist> 93 <PathTwist>0</PathTwist>
92 <PathTwistBegin>0</PathTwistBegin> 94 <PathTwistBegin>0</PathTwistBegin>
93 <PCode>9</PCode> 95 <PCode>9</PCode>
94 <ProfileBegin>0</ProfileBegin> 96 <ProfileBegin>0</ProfileBegin>
95 <ProfileEnd>0</ProfileEnd> 97 <ProfileEnd>0</ProfileEnd>
96 <ProfileHollow>0</ProfileHollow> 98 <ProfileHollow>0</ProfileHollow>
97 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> 99 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale>
98 <State>0</State> 100 <State>0</State>
99 <ProfileShape>Square</ProfileShape> 101 <ProfileShape>Square</ProfileShape>
100 <HollowShape>Same</HollowShape> 102 <HollowShape>Same</HollowShape>
101 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture> 103 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture>
102 <SculptType>0</SculptType><SculptData /> 104 <SculptType>0</SculptType><SculptData />
103 <FlexiSoftness>0</FlexiSoftness> 105 <FlexiSoftness>0</FlexiSoftness>
104 <FlexiTension>0</FlexiTension> 106 <FlexiTension>0</FlexiTension>
105 <FlexiDrag>0</FlexiDrag> 107 <FlexiDrag>0</FlexiDrag>
106 <FlexiGravity>0</FlexiGravity> 108 <FlexiGravity>0</FlexiGravity>
107 <FlexiWind>0</FlexiWind> 109 <FlexiWind>0</FlexiWind>
108 <FlexiForceX>0</FlexiForceX> 110 <FlexiForceX>0</FlexiForceX>
109 <FlexiForceY>0</FlexiForceY> 111 <FlexiForceY>0</FlexiForceY>
110 <FlexiForceZ>0</FlexiForceZ> 112 <FlexiForceZ>0</FlexiForceZ>
111 <LightColorR>0</LightColorR> 113 <LightColorR>0</LightColorR>
112 <LightColorG>0</LightColorG> 114 <LightColorG>0</LightColorG>
113 <LightColorB>0</LightColorB> 115 <LightColorB>0</LightColorB>
114 <LightColorA>1</LightColorA> 116 <LightColorA>1</LightColorA>
115 <LightRadius>0</LightRadius> 117 <LightRadius>0</LightRadius>
116 <LightCutoff>0</LightCutoff> 118 <LightCutoff>0</LightCutoff>
117 <LightFalloff>0</LightFalloff> 119 <LightFalloff>0</LightFalloff>
118 <LightIntensity>1</LightIntensity> 120 <LightIntensity>1</LightIntensity>
119 <FlexiEntry>false</FlexiEntry> 121 <FlexiEntry>false</FlexiEntry>
120 <LightEntry>false</LightEntry> 122 <LightEntry>false</LightEntry>
121 <SculptEntry>false</SculptEntry> 123 <SculptEntry>false</SculptEntry>
122 </Shape> 124 </Shape>
123 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> 125 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale>
124 <UpdateFlag>0</UpdateFlag> 126 <UpdateFlag>0</UpdateFlag>
125 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation> 127 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation>
126 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition> 128 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition>
127 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL> 129 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL>
128 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL> 130 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL>
129 <ParentID>0</ParentID> 131 <ParentID>0</ParentID>
130 <CreationDate>1211330445</CreationDate> 132 <CreationDate>1211330445</CreationDate>
131 <Category>0</Category> 133 <Category>0</Category>
132 <SalePrice>0</SalePrice> 134 <SalePrice>0</SalePrice>
133 <ObjectSaleType>0</ObjectSaleType> 135 <ObjectSaleType>0</ObjectSaleType>
134 <OwnershipCost>0</OwnershipCost> 136 <OwnershipCost>0</OwnershipCost>
135 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID> 137 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID>
136 <OwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></OwnerID> 138 <OwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></OwnerID>
137 <LastOwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></LastOwnerID> 139 <LastOwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></LastOwnerID>
138 <BaseMask>2147483647</BaseMask> 140 <BaseMask>2147483647</BaseMask>
139 <OwnerMask>2147483647</OwnerMask> 141 <OwnerMask>2147483647</OwnerMask>
140 <GroupMask>0</GroupMask> 142 <GroupMask>0</GroupMask>
141 <EveryoneMask>0</EveryoneMask> 143 <EveryoneMask>0</EveryoneMask>
142 <NextOwnerMask>2147483647</NextOwnerMask> 144 <NextOwnerMask>2147483647</NextOwnerMask>
143 <Flags>None</Flags> 145 <Flags>None</Flags>
144 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> 146 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
145 <CollisionSoundVolume>0</CollisionSoundVolume> 147 <CollisionSoundVolume>0</CollisionSoundVolume>
146 </SceneObjectPart> 148 <DynAttrs>
147 </RootPart> 149 <llsd>
148 <OtherParts /> 150 <map>
149 </SceneObjectGroup>"; 151 <key>MyNamespace</key>
150 152 <map>
151 private string badFloatsXml = @" 153 <key>MyStore</key>
154 <map>
155 <key>the answer</key>
156 <integer>42</integer>
157 </map>
158 </map>
159 </map>
160 </llsd>
161 </DynAttrs>
162 </SceneObjectPart>
163 </RootPart>";
164
165 private const string ObjectWithNoOtherPartsXml = ObjectRootPartStubXml +
166@"
167 <OtherParts />
168</SceneObjectGroup>";
169
170 private const string ObjectWithOtherPartsXml = ObjectRootPartStubXml +
171@"
172 <OtherParts>
173 <Part>
174 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
175 <AllowedDrop>false</AllowedDrop>
176 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID>
177 <FolderID><Guid>9958feb1-02a6-49e4-a4ce-eba6f578ee13</Guid></FolderID>
178 <InventorySerial>3</InventorySerial>
179 <UUID><Guid>9958feb1-02a6-49e4-a4ce-eba6f578ee13</Guid></UUID>
180 <LocalId>1154704500</LocalId>
181 <Name>Alien Head 1</Name>
182 <Material>3</Material>
183 <PassTouches>false</PassTouches>
184 <PassCollisions>false</PassCollisions>
185 <RegionHandle>21990232560640000</RegionHandle>
186 <ScriptAccessPin>0</ScriptAccessPin>
187 <GroupPosition><X>125.5655</X><Y>127.346</Y><Z>22.48036</Z></GroupPosition>
188 <OffsetPosition><X>-0.2171936</X><Y>0.1083984</Y><Z>0.0009994507</Z></OffsetPosition>
189 <RotationOffset><X>-0.5122106</X><Y>0.4851225</Y><Z>-0.4957454</Z><W>0.5064908</W></RotationOffset>
190 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity>
191 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity>
192 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration>
193 <Description>(No Description)</Description>
194 <Color><R>0</R><G>0</G><B>0</B><A>255</A></Color>
195 <Text/>
196 <SitName/>
197 <TouchName/>
198 <LinkNum>253</LinkNum>
199 <ClickAction>0</ClickAction>
200 <Shape>
201 <ProfileCurve>5</ProfileCurve>
202 <TextureEntry>Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</TextureEntry>
203 <ExtraParams>AA==</ExtraParams>
204 <PathBegin>0</PathBegin>
205 <PathCurve>32</PathCurve>
206 <PathEnd>0</PathEnd>
207 <PathRadiusOffset>0</PathRadiusOffset>
208 <PathRevolutions>0</PathRevolutions>
209 <PathScaleX>100</PathScaleX>
210 <PathScaleY>100</PathScaleY>
211 <PathShearX>0</PathShearX>
212 <PathShearY>0</PathShearY>
213 <PathSkew>0</PathSkew>
214 <PathTaperX>0</PathTaperX>
215 <PathTaperY>0</PathTaperY>
216 <PathTwist>0</PathTwist>
217 <PathTwistBegin>0</PathTwistBegin>
218 <PCode>9</PCode>
219 <ProfileBegin>0</ProfileBegin>
220 <ProfileEnd>0</ProfileEnd>
221 <ProfileHollow>0</ProfileHollow>
222 <State>9</State>
223 <LastAttachPoint>0</LastAttachPoint>
224 <ProfileShape>HalfCircle</ProfileShape>
225 <HollowShape>Same</HollowShape>
226 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture>
227 <SculptType>0</SculptType>
228 <FlexiSoftness>0</FlexiSoftness>
229 <FlexiTension>0</FlexiTension>
230 <FlexiDrag>0</FlexiDrag>
231 <FlexiGravity>0</FlexiGravity>
232 <FlexiWind>0</FlexiWind>
233 <FlexiForceX>0</FlexiForceX>
234 <FlexiForceY>0</FlexiForceY>
235 <FlexiForceZ>0</FlexiForceZ>
236 <LightColorR>0</LightColorR>
237 <LightColorG>0</LightColorG>
238 <LightColorB>0</LightColorB>
239 <LightColorA>1</LightColorA>
240 <LightRadius>0</LightRadius>
241 <LightCutoff>0</LightCutoff>
242 <LightFalloff>0</LightFalloff>
243 <LightIntensity>1</LightIntensity>
244 <FlexiEntry>false</FlexiEntry>
245 <LightEntry>false</LightEntry>
246 <SculptEntry>false</SculptEntry>
247 </Shape>
248 <Scale><X>0.1148195</X><Y>0.0143891</Y><Z>0.02768878</Z></Scale>
249 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation>
250 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition>
251 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL>
252 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL>
253 <ParentID>1154704499</ParentID>
254 <CreationDate>1256611042</CreationDate>
255 <Category>0</Category>
256 <SalePrice>10</SalePrice>
257 <ObjectSaleType>0</ObjectSaleType>
258 <OwnershipCost>0</OwnershipCost>
259 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID>
260 <OwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></OwnerID>
261 <LastOwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></LastOwnerID>
262 <BaseMask>647168</BaseMask>
263 <OwnerMask>647168</OwnerMask>
264 <GroupMask>0</GroupMask>
265 <EveryoneMask>0</EveryoneMask>
266 <NextOwnerMask>581632</NextOwnerMask>
267 <Flags>None</Flags>
268 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
269 <CollisionSoundVolume>0</CollisionSoundVolume>
270 <AttachedPos><X>0</X><Y>0</Y><Z>0</Z></AttachedPos>
271 <TextureAnimation/>
272 <ParticleSystem/>
273 <PayPrice0>-2</PayPrice0>
274 <PayPrice1>-2</PayPrice1>
275 <PayPrice2>-2</PayPrice2>
276 <PayPrice3>-2</PayPrice3>
277 <PayPrice4>-2</PayPrice4>
278 </SceneObjectPart>
279 </Part>
280 <Part>
281 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
282 <AllowedDrop>false</AllowedDrop>
283 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID>
284 <FolderID><Guid>674b6b86-f5aa-439a-8e00-0d75bc08c80a</Guid></FolderID>
285 <InventorySerial>3</InventorySerial>
286 <UUID><Guid>674b6b86-f5aa-439a-8e00-0d75bc08c80a</Guid></UUID>
287 <LocalId>1154704501</LocalId>
288 <Name>Alien Head 2</Name>
289 <Material>3</Material>
290 <PassTouches>false</PassTouches>
291 <PassCollisions>false</PassCollisions>
292 <RegionHandle>21990232560640000</RegionHandle>
293 <ScriptAccessPin>0</ScriptAccessPin>
294 <GroupPosition><X>125.5655</X><Y>127.346</Y><Z>22.48036</Z></GroupPosition>
295 <OffsetPosition><X>-0.2490997</X><Y>0.08520126</Y><Z>0.0009002686</Z></OffsetPosition>
296 <RotationOffset><X>-0.4765368</X><Y>0.5194498</Y><Z>-0.5301372</Z><W>0.4712104</W></RotationOffset>
297 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity>
298 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity>
299 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration>
300 <Description>(No Description)</Description>
301 <Color><R>0</R><G>0</G><B>0</B><A>255</A></Color>
302 <Text/>
303 <SitName/>
304 <TouchName/>
305 <LinkNum>252</LinkNum>
306 <ClickAction>0</ClickAction>
307 <Shape>
308 <ProfileCurve>0</ProfileCurve>
309 <TextureEntry>Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</TextureEntry>
310 <ExtraParams>AA==</ExtraParams>
311 <PathBegin>0</PathBegin>
312 <PathCurve>32</PathCurve>
313 <PathEnd>0</PathEnd>
314 <PathRadiusOffset>0</PathRadiusOffset>
315 <PathRevolutions>0</PathRevolutions>
316 <PathScaleX>100</PathScaleX>
317 <PathScaleY>150</PathScaleY>
318 <PathShearX>0</PathShearX>
319 <PathShearY>0</PathShearY>
320 <PathSkew>0</PathSkew>
321 <PathTaperX>0</PathTaperX>
322 <PathTaperY>0</PathTaperY>
323 <PathTwist>0</PathTwist>
324 <PathTwistBegin>0</PathTwistBegin>
325 <PCode>9</PCode>
326 <ProfileBegin>0</ProfileBegin>
327 <ProfileEnd>0</ProfileEnd>
328 <ProfileHollow>0</ProfileHollow>
329 <State>9</State>
330 <LastAttachPoint>0</LastAttachPoint>
331 <ProfileShape>Circle</ProfileShape>
332 <HollowShape>Same</HollowShape>
333 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture>
334 <SculptType>0</SculptType>
335 <FlexiSoftness>0</FlexiSoftness>
336 <FlexiTension>0</FlexiTension>
337 <FlexiDrag>0</FlexiDrag>
338 <FlexiGravity>0</FlexiGravity>
339 <FlexiWind>0</FlexiWind>
340 <FlexiForceX>0</FlexiForceX>
341 <FlexiForceY>0</FlexiForceY>
342 <FlexiForceZ>0</FlexiForceZ>
343 <LightColorR>0</LightColorR>
344 <LightColorG>0</LightColorG>
345 <LightColorB>0</LightColorB>
346 <LightColorA>1</LightColorA>
347 <LightRadius>0</LightRadius>
348 <LightCutoff>0</LightCutoff>
349 <LightFalloff>0</LightFalloff>
350 <LightIntensity>1</LightIntensity>
351 <FlexiEntry>false</FlexiEntry>
352 <LightEntry>false</LightEntry>
353 <SculptEntry>false</SculptEntry>
354 </Shape>
355 <Scale><X>0.03574385</X><Y>0.05958032</Y><Z>0.04764182</Z></Scale>
356 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation>
357 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition>
358 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL>
359 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL>
360 <ParentID>1154704499</ParentID>
361 <CreationDate>1256611042</CreationDate>
362 <Category>0</Category>
363 <SalePrice>10</SalePrice>
364 <ObjectSaleType>0</ObjectSaleType>
365 <OwnershipCost>0</OwnershipCost>
366 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID>
367 <OwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></OwnerID>
368 <LastOwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></LastOwnerID>
369 <BaseMask>647168</BaseMask>
370 <OwnerMask>647168</OwnerMask>
371 <GroupMask>0</GroupMask>
372 <EveryoneMask>0</EveryoneMask>
373 <NextOwnerMask>581632</NextOwnerMask>
374 <Flags>None</Flags>
375 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
376 <CollisionSoundVolume>0</CollisionSoundVolume>
377 <AttachedPos><X>0</X><Y>0</Y><Z>0</Z></AttachedPos>
378 <TextureAnimation/>
379 <ParticleSystem/>
380 <PayPrice0>-2</PayPrice0>
381 <PayPrice1>-2</PayPrice1>
382 <PayPrice2>-2</PayPrice2>
383 <PayPrice3>-2</PayPrice3>
384 <PayPrice4>-2</PayPrice4>
385 </SceneObjectPart>
386 </Part>
387 </OtherParts>
388</SceneObjectGroup>";
389
390 private const string ObjectWithBadFloatsXml = @"
152 <SceneObjectGroup> 391 <SceneObjectGroup>
153 <RootPart> 392 <RootPart>
154 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 393 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
@@ -255,7 +494,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
255 <OtherParts /> 494 <OtherParts />
256 </SceneObjectGroup>"; 495 </SceneObjectGroup>";
257 496
258 private string xml2 = @" 497 private const string ObjectWithNoPartsXml2 = @"
259 <SceneObjectGroup> 498 <SceneObjectGroup>
260 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 499 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
261 <CreatorID><UUID>b46ef588-411e-4a8b-a284-d7dcfe8e74ef</UUID></CreatorID> 500 <CreatorID><UUID>b46ef588-411e-4a8b-a284-d7dcfe8e74ef</UUID></CreatorID>
@@ -331,6 +570,20 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
331 <EveryoneMask>0</EveryoneMask> 570 <EveryoneMask>0</EveryoneMask>
332 <NextOwnerMask>2147483647</NextOwnerMask> 571 <NextOwnerMask>2147483647</NextOwnerMask>
333 <Flags>None</Flags> 572 <Flags>None</Flags>
573 <DynAttrs>
574 <llsd>
575 <map>
576 <key>MyNamespace</key>
577 <map>
578 <key>MyStore</key>
579 <map>
580 <key>last words</key>
581 <string>Rosebud</string>
582 </map>
583 </map>
584 </map>
585 </llsd>
586 </DynAttrs>
334 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> 587 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar>
335 </SceneObjectPart> 588 </SceneObjectPart>
336 <OtherParts /> 589 <OtherParts />
@@ -348,17 +601,58 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
348 } 601 }
349 602
350 [Test] 603 [Test]
351 public void TestDeserializeXml() 604 public void TestDeserializeXmlObjectWithNoOtherParts()
352 { 605 {
353 TestHelpers.InMethod(); 606 TestHelpers.InMethod();
354 //log4net.Config.XmlConfigurator.Configure(); 607 TestHelpers.EnableLogging();
355 608
356 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(xml); 609 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithNoOtherPartsXml);
357 SceneObjectPart rootPart = so.RootPart; 610 SceneObjectPart rootPart = so.RootPart;
358 611
359 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); 612 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
360 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); 613 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
361 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); 614 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide"));
615 OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore");
616 Assert.AreEqual(42, store["the answer"].AsInteger());
617
618 // TODO: Check other properties
619 }
620
621 [Test]
622 public void TestDeserializeXmlObjectWithOtherParts()
623 {
624 TestHelpers.InMethod();
625 TestHelpers.EnableLogging();
626
627 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithOtherPartsXml);
628 SceneObjectPart[] parts = so.Parts;
629 Assert.AreEqual(3, so.Parts.Length);
630
631 {
632 SceneObjectPart part = parts[0];
633
634 Assert.That(part.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
635 Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
636 Assert.That(part.Name, Is.EqualTo("PrimMyRide"));
637 OSDMap store = part.DynAttrs.GetStore("MyNamespace", "MyStore");
638 Assert.AreEqual(42, store["the answer"].AsInteger());
639 }
640
641 {
642 SceneObjectPart part = parts[1];
643
644 Assert.That(part.UUID, Is.EqualTo(new UUID("9958feb1-02a6-49e4-a4ce-eba6f578ee13")));
645 Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
646 Assert.That(part.Name, Is.EqualTo("Alien Head 1"));
647 }
648
649 {
650 SceneObjectPart part = parts[2];
651
652 Assert.That(part.UUID, Is.EqualTo(new UUID("674b6b86-f5aa-439a-8e00-0d75bc08c80a")));
653 Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
654 Assert.That(part.Name, Is.EqualTo("Alien Head 2"));
655 }
362 656
363 // TODO: Check other properties 657 // TODO: Check other properties
364 } 658 }
@@ -369,7 +663,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
369 TestHelpers.InMethod(); 663 TestHelpers.InMethod();
370// log4net.Config.XmlConfigurator.Configure(); 664// log4net.Config.XmlConfigurator.Configure();
371 665
372 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(badFloatsXml); 666 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithBadFloatsXml);
373 SceneObjectPart rootPart = so.RootPart; 667 SceneObjectPart rootPart = so.RootPart;
374 668
375 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); 669 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
@@ -409,6 +703,15 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
409 rp.CreatorID = rpCreatorId; 703 rp.CreatorID = rpCreatorId;
410 rp.Shape = shape; 704 rp.Shape = shape;
411 705
706 string daNamespace = "MyNamespace";
707 string daStoreName = "MyStore";
708 string daKey = "foo";
709 string daValue = "bar";
710 OSDMap myStore = new OSDMap();
711 myStore.Add(daKey, daValue);
712 rp.DynAttrs = new DAMap();
713 rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore);
714
412 SceneObjectGroup so = new SceneObjectGroup(rp); 715 SceneObjectGroup so = new SceneObjectGroup(rp);
413 716
414 // Need to add the object to the scene so that the request to get script state succeeds 717 // Need to add the object to the scene so that the request to get script state succeeds
@@ -424,6 +727,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
424 UUID uuid = UUID.Zero; 727 UUID uuid = UUID.Zero;
425 string name = null; 728 string name = null;
426 UUID creatorId = UUID.Zero; 729 UUID creatorId = UUID.Zero;
730 DAMap daMap = null;
427 731
428 while (xtr.Read() && xtr.Name != "SceneObjectPart") 732 while (xtr.Read() && xtr.Name != "SceneObjectPart")
429 { 733 {
@@ -449,6 +753,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
449 creatorId = UUID.Parse(xtr.ReadElementString("UUID")); 753 creatorId = UUID.Parse(xtr.ReadElementString("UUID"));
450 xtr.ReadEndElement(); 754 xtr.ReadEndElement();
451 break; 755 break;
756 case "DynAttrs":
757 daMap = new DAMap();
758 daMap.ReadXml(xtr);
759 break;
452 } 760 }
453 } 761 }
454 762
@@ -462,6 +770,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
462 Assert.That(uuid, Is.EqualTo(rpUuid)); 770 Assert.That(uuid, Is.EqualTo(rpUuid));
463 Assert.That(name, Is.EqualTo(rpName)); 771 Assert.That(name, Is.EqualTo(rpName));
464 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 772 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
773 Assert.NotNull(daMap);
774 Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString());
465 } 775 }
466 776
467 [Test] 777 [Test]
@@ -470,12 +780,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
470 TestHelpers.InMethod(); 780 TestHelpers.InMethod();
471 //log4net.Config.XmlConfigurator.Configure(); 781 //log4net.Config.XmlConfigurator.Configure();
472 782
473 SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(xml2); 783 SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(ObjectWithNoPartsXml2);
474 SceneObjectPart rootPart = so.RootPart; 784 SceneObjectPart rootPart = so.RootPart;
475 785
476 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); 786 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946")));
477 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); 787 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef")));
478 Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); 788 Assert.That(rootPart.Name, Is.EqualTo("PrimFun"));
789 OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore");
790 Assert.AreEqual("Rosebud", store["last words"].AsString());
479 791
480 // TODO: Check other properties 792 // TODO: Check other properties
481 } 793 }
@@ -500,6 +812,15 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
500 rp.CreatorID = rpCreatorId; 812 rp.CreatorID = rpCreatorId;
501 rp.Shape = shape; 813 rp.Shape = shape;
502 814
815 string daNamespace = "MyNamespace";
816 string daStoreName = "MyStore";
817 string daKey = "foo";
818 string daValue = "bar";
819 OSDMap myStore = new OSDMap();
820 myStore.Add(daKey, daValue);
821 rp.DynAttrs = new DAMap();
822 rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore);
823
503 SceneObjectGroup so = new SceneObjectGroup(rp); 824 SceneObjectGroup so = new SceneObjectGroup(rp);
504 825
505 // Need to add the object to the scene so that the request to get script state succeeds 826 // Need to add the object to the scene so that the request to get script state succeeds
@@ -516,6 +837,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
516 UUID uuid = UUID.Zero; 837 UUID uuid = UUID.Zero;
517 string name = null; 838 string name = null;
518 UUID creatorId = UUID.Zero; 839 UUID creatorId = UUID.Zero;
840 DAMap daMap = null;
519 841
520 while (xtr.Read() && xtr.Name != "SceneObjectPart") 842 while (xtr.Read() && xtr.Name != "SceneObjectPart")
521 { 843 {
@@ -537,6 +859,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
537 creatorId = UUID.Parse(xtr.ReadElementString("Guid")); 859 creatorId = UUID.Parse(xtr.ReadElementString("Guid"));
538 xtr.ReadEndElement(); 860 xtr.ReadEndElement();
539 break; 861 break;
862 case "DynAttrs":
863 daMap = new DAMap();
864 daMap.ReadXml(xtr);
865 break;
540 } 866 }
541 } 867 }
542 868
@@ -549,6 +875,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
549 Assert.That(uuid, Is.EqualTo(rpUuid)); 875 Assert.That(uuid, Is.EqualTo(rpUuid));
550 Assert.That(name, Is.EqualTo(rpName)); 876 Assert.That(name, Is.EqualTo(rpName));
551 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 877 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
878 Assert.NotNull(daMap);
879 Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString());
552 } 880 }
553 } 881 }
554} \ No newline at end of file 882} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index 883045a..d093224 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -369,6 +369,15 @@ namespace OpenSim.Region.CoreModules.World.Sound
369 }); 369 });
370 } 370 }
371 371
372 public void SetSoundQueueing(UUID objectID, bool shouldQueue)
373 {
374 SceneObjectPart part;
375 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
376 return;
377
378 part.SoundQueueing = shouldQueue;
379 }
380
372 #endregion 381 #endregion
373 } 382 }
374} 383}
diff --git a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
index a321c09..d0318eb 100644
--- a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
@@ -68,9 +68,6 @@ namespace OpenSim.Region.CoreModules
68 // updating those region settings in GenSunPos() 68 // updating those region settings in GenSunPos()
69 private bool receivedEstateToolsSunUpdate = false; 69 private bool receivedEstateToolsSunUpdate = false;
70 70
71 // Configurable values
72 private string m_RegionMode = "SL";
73
74 // Sun's position information is updated and sent to clients every m_UpdateInterval frames 71 // Sun's position information is updated and sent to clients every m_UpdateInterval frames
75 private int m_UpdateInterval = 0; 72 private int m_UpdateInterval = 0;
76 73
@@ -90,7 +87,6 @@ namespace OpenSim.Region.CoreModules
90 // private double m_longitude = 0; 87 // private double m_longitude = 0;
91 // private double m_latitude = 0; 88 // private double m_latitude = 0;
92 // Configurable defaults Defaults close to SL 89 // Configurable defaults Defaults close to SL
93 private string d_mode = "SL";
94 private int d_frame_mod = 100; // Every 10 seconds (actually less) 90 private int d_frame_mod = 100; // Every 10 seconds (actually less)
95 private double d_day_length = 4; // A VW day is 4 RW hours long 91 private double d_day_length = 4; // A VW day is 4 RW hours long
96 private int d_year_length = 60; // There are 60 VW days in a VW year 92 private int d_year_length = 60; // There are 60 VW days in a VW year
@@ -134,12 +130,15 @@ namespace OpenSim.Region.CoreModules
134 130
135 private const int TICKS_PER_SECOND = 10000000; 131 private const int TICKS_PER_SECOND = 10000000;
136 132
133 private ulong m_CurrentTimeOffset = 0;
134
137 // Current time in elapsed seconds since Jan 1st 1970 135 // Current time in elapsed seconds since Jan 1st 1970
138 private ulong CurrentTime 136 private ulong CurrentTime
139 { 137 {
140 get 138 get
141 { 139 {
142 return (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND); 140 ulong ctime = (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND);
141 return ctime + m_CurrentTimeOffset;
143 } 142 }
144 } 143 }
145 144
@@ -252,21 +251,18 @@ namespace OpenSim.Region.CoreModules
252 } 251 }
253 252
254 // TODO: Decouple this, so we can get rid of Linden Hour info 253 // TODO: Decouple this, so we can get rid of Linden Hour info
255 // Update Region infor with new Sun Position and Hour 254 // Update Region with new Sun Vector
256 // set estate settings for region access to sun position 255 // set estate settings for region access to sun position
257 if (receivedEstateToolsSunUpdate) 256 if (receivedEstateToolsSunUpdate)
258 { 257 {
259 m_scene.RegionInfo.RegionSettings.SunVector = Position; 258 m_scene.RegionInfo.RegionSettings.SunVector = Position;
260 m_scene.RegionInfo.RegionSettings.SunPosition = GetCurrentTimeAsLindenSunHour();
261 } 259 }
262 } 260 }
263 261
264 private float GetCurrentTimeAsLindenSunHour() 262 private float GetCurrentTimeAsLindenSunHour()
265 { 263 {
266 if (m_SunFixed) 264 float curtime = m_SunFixed ? m_SunFixedHour : GetCurrentSunHour();
267 return m_SunFixedHour + 6; 265 return (curtime + 6.0f) % 24.0f;
268
269 return GetCurrentSunHour() + 6.0f;
270 } 266 }
271 267
272 #region INonSharedRegion Methods 268 #region INonSharedRegion Methods
@@ -292,8 +288,6 @@ namespace OpenSim.Region.CoreModules
292 try 288 try
293 { 289 {
294 // Mode: determines how the sun is handled 290 // Mode: determines how the sun is handled
295 m_RegionMode = config.Configs["Sun"].GetString("mode", d_mode);
296 // Mode: determines how the sun is handled
297 // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude); 291 // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude);
298 // Mode: determines how the sun is handled 292 // Mode: determines how the sun is handled
299 // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude); 293 // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude);
@@ -315,7 +309,6 @@ namespace OpenSim.Region.CoreModules
315 catch (Exception e) 309 catch (Exception e)
316 { 310 {
317 m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message); 311 m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message);
318 m_RegionMode = d_mode;
319 m_YearLengthDays = d_year_length; 312 m_YearLengthDays = d_year_length;
320 m_DayLengthHours = d_day_length; 313 m_DayLengthHours = d_day_length;
321 m_HorizonShift = d_day_night; 314 m_HorizonShift = d_day_night;
@@ -326,40 +319,28 @@ namespace OpenSim.Region.CoreModules
326 // m_longitude = d_longitude; 319 // m_longitude = d_longitude;
327 } 320 }
328 321
329 switch (m_RegionMode) 322 SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
330 { 323 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
331 case "T1":
332 default:
333 case "SL":
334 // Time taken to complete a cycle (day and season)
335
336 SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
337 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
338
339 // Ration of real-to-virtual time
340 324
341 // VWTimeRatio = 24/m_day_length; 325 // Ration of real-to-virtual time
342 326
343 // Speed of rotation needed to complete a cycle in the 327 // VWTimeRatio = 24/m_day_length;
344 // designated period (day and season)
345 328
346 SunSpeed = m_SunCycle/SecondsPerSunCycle; 329 // Speed of rotation needed to complete a cycle in the
347 SeasonSpeed = m_SeasonalCycle/SecondsPerYear; 330 // designated period (day and season)
348 331
349 // Horizon translation 332 SunSpeed = m_SunCycle/SecondsPerSunCycle;
333 SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
350 334
351 HorizonShift = m_HorizonShift; // Z axis translation 335 // Horizon translation
352 // HoursToRadians = (SunCycle/24)*VWTimeRatio;
353 336
354 m_log.Debug("[SUN]: Mode is " + m_RegionMode); 337 HorizonShift = m_HorizonShift; // Z axis translation
355 m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days"); 338 // HoursToRadians = (SunCycle/24)*VWTimeRatio;
356 m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift);
357 m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale);
358 m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames");
359
360 break;
361 }
362 339
340 m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days");
341 m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift);
342 m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale);
343 m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames");
363 } 344 }
364 345
365 public Type ReplaceableInterface 346 public Type ReplaceableInterface
@@ -386,7 +367,8 @@ namespace OpenSim.Region.CoreModules
386 string sunCommand = string.Format("sun {0}", kvp.Key); 367 string sunCommand = string.Format("sun {0}", kvp.Key);
387 m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand); 368 m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand);
388 } 369 }
389 370 m_scene.AddCommand("Regions", this, "sun help", "sun help", "list parameters that can be changed", "", HandleSunConsoleCommand);
371 m_scene.AddCommand("Regions", this, "sun list", "sun list", "list parameters that can be changed", "", HandleSunConsoleCommand);
390 ready = true; 372 ready = true;
391 } 373 }
392 374
@@ -395,7 +377,7 @@ namespace OpenSim.Region.CoreModules
395 ready = false; 377 ready = false;
396 378
397 // Remove our hooks 379 // Remove our hooks
398 m_scene.EventManager.OnFrame -= SunUpdate; 380 m_scene.EventManager.OnFrame -= SunUpdate;
399 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; 381 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel;
400 m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; 382 m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate;
401 m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; 383 m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour;
@@ -420,23 +402,22 @@ namespace OpenSim.Region.CoreModules
420 402
421 public void SunToClient(IClientAPI client) 403 public void SunToClient(IClientAPI client)
422 { 404 {
423 if (m_RegionMode != "T1") 405 if (ready)
424 { 406 {
425 if (ready) 407 if (m_SunFixed)
426 { 408 {
427 if (m_SunFixed) 409 // m_log.DebugFormat("[SUN]: Fixed SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ",
428 { 410 // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
429 // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); 411 client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
430 client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); 412 }
431 } 413 else
432 else 414 {
433 { 415 // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ",
434 // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); 416 // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
435 client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); 417 client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
436 }
437 } 418 }
438 } 419 }
439 } 420 }
440 421
441 public void SunUpdate() 422 public void SunUpdate()
442 { 423 {
@@ -459,26 +440,33 @@ namespace OpenSim.Region.CoreModules
459 SunToClient(avatar.ControllingClient); 440 SunToClient(avatar.ControllingClient);
460 } 441 }
461 442
462 /// <summary> 443 public void EstateToolsSunUpdate(ulong regionHandle)
463 ///
464 /// </summary>
465 /// <param name="regionHandle"></param>
466 /// <param name="FixedTime">Is the sun's position fixed?</param>
467 /// <param name="useEstateTime">Use the Region or Estate Sun hour?</param>
468 /// <param name="FixedSunHour">What hour of the day is the Sun Fixed at?</param>
469 public void EstateToolsSunUpdate(ulong regionHandle, bool FixedSun, bool useEstateTime, float FixedSunHour)
470 { 444 {
471 if (m_scene.RegionInfo.RegionHandle == regionHandle) 445 if (m_scene.RegionInfo.RegionHandle == regionHandle)
472 { 446 {
473 // Must limit the Sun Hour to 0 ... 24 447 float sunFixedHour;
474 while (FixedSunHour > 24.0f) 448 bool fixedSun;
475 FixedSunHour -= 24;
476 449
477 while (FixedSunHour < 0) 450 if (m_scene.RegionInfo.RegionSettings.UseEstateSun)
478 FixedSunHour += 24; 451 {
452 sunFixedHour = (float)m_scene.RegionInfo.EstateSettings.SunPosition;
453 fixedSun = m_scene.RegionInfo.EstateSettings.FixedSun;
454 }
455 else
456 {
457 sunFixedHour = (float)m_scene.RegionInfo.RegionSettings.SunPosition - 6.0f;
458 fixedSun = m_scene.RegionInfo.RegionSettings.FixedSun;
459 }
460
461 // Must limit the Sun Hour to 0 ... 24
462 while (sunFixedHour > 24.0f)
463 sunFixedHour -= 24;
479 464
480 m_SunFixedHour = FixedSunHour; 465 while (sunFixedHour < 0)
481 m_SunFixed = FixedSun; 466 sunFixedHour += 24;
467
468 m_SunFixedHour = sunFixedHour;
469 m_SunFixed = fixedSun;
482 470
483 // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); 471 // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString());
484 // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); 472 // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString());
@@ -501,7 +489,7 @@ namespace OpenSim.Region.CoreModules
501 { 489 {
502 m_scene.ForEachRootClient(delegate(IClientAPI client) 490 m_scene.ForEachRootClient(delegate(IClientAPI client)
503 { 491 {
504 SunToClient(client); 492 SunToClient(client);
505 }); 493 });
506 } 494 }
507 495
@@ -526,6 +514,9 @@ namespace OpenSim.Region.CoreModules
526 case "update_interval": 514 case "update_interval":
527 return m_UpdateInterval; 515 return m_UpdateInterval;
528 516
517 case "current_time":
518 return GetCurrentTimeAsLindenSunHour();
519
529 default: 520 default:
530 throw new Exception("Unknown sun parameter."); 521 throw new Exception("Unknown sun parameter.");
531 } 522 }
@@ -533,7 +524,51 @@ namespace OpenSim.Region.CoreModules
533 524
534 public void SetSunParameter(string param, double value) 525 public void SetSunParameter(string param, double value)
535 { 526 {
536 HandleSunConsoleCommand("sun", new string[] {param, value.ToString() }); 527 switch (param)
528 {
529 case "year_length":
530 m_YearLengthDays = (int)value;
531 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
532 SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
533 break;
534
535 case "day_length":
536 m_DayLengthHours = value;
537 SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
538 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
539 SunSpeed = m_SunCycle/SecondsPerSunCycle;
540 SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
541 break;
542
543 case "day_night_offset":
544 m_HorizonShift = value;
545 HorizonShift = m_HorizonShift;
546 break;
547
548 case "day_time_sun_hour_scale":
549 m_DayTimeSunHourScale = value;
550 break;
551
552 case "update_interval":
553 m_UpdateInterval = (int)value;
554 break;
555
556 case "current_time":
557 value = (value + 18.0) % 24.0;
558 // set the current offset so that the effective sun time is the parameter
559 m_CurrentTimeOffset = 0; // clear this first so we use raw time
560 m_CurrentTimeOffset = (ulong)(SecondsPerSunCycle * value/ 24.0) - (CurrentTime % SecondsPerSunCycle);
561 break;
562
563 default:
564 throw new Exception("Unknown sun parameter.");
565 }
566
567 // Generate shared values
568 GenSunPos();
569
570 // When sun settings are updated, we should update all clients with new settings.
571 SunUpdateToAllClients();
537 } 572 }
538 573
539 public float GetCurrentSunHour() 574 public float GetCurrentSunHour()
@@ -566,7 +601,7 @@ namespace OpenSim.Region.CoreModules
566 601
567 foreach (string output in ParseCmdParams(cmdparams)) 602 foreach (string output in ParseCmdParams(cmdparams))
568 { 603 {
569 m_log.Info("[SUN] " + output); 604 MainConsole.Instance.Output(output);
570 } 605 }
571 } 606 }
572 607
@@ -575,10 +610,11 @@ namespace OpenSim.Region.CoreModules
575 Dictionary<string, string> Params = new Dictionary<string, string>(); 610 Dictionary<string, string> Params = new Dictionary<string, string>();
576 611
577 Params.Add("year_length", "number of days to a year"); 612 Params.Add("year_length", "number of days to a year");
578 Params.Add("day_length", "number of seconds to a day"); 613 Params.Add("day_length", "number of hours to a day");
579 Params.Add("day_night_offset", "induces a horizon shift"); 614 Params.Add("day_night_offset", "induces a horizon shift");
580 Params.Add("update_interval", "how often to update the sun's position in frames"); 615 Params.Add("update_interval", "how often to update the sun's position in frames");
581 Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio"); 616 Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio");
617 Params.Add("current_time", "time in seconds of the simulator");
582 618
583 return Params; 619 return Params;
584 } 620 }
@@ -612,46 +648,15 @@ namespace OpenSim.Region.CoreModules
612 } 648 }
613 else if (args.Length == 3) 649 else if (args.Length == 3)
614 { 650 {
615 float value = 0.0f; 651 double value = 0.0;
616 if (!float.TryParse(args[2], out value)) 652 if (! double.TryParse(args[2], out value))
617 { 653 {
618 Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2])); 654 Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2]));
655 return Output;
619 } 656 }
620 657
621 switch (args[1].ToLower()) 658 SetSunParameter(args[1].ToLower(), value);
622 {
623 case "year_length":
624 m_YearLengthDays = (int)value;
625 break;
626
627 case "day_length":
628 m_DayLengthHours = value;
629 break;
630
631 case "day_night_offset":
632 m_HorizonShift = value;
633 break;
634
635 case "day_time_sun_hour_scale":
636 m_DayTimeSunHourScale = value;
637 break;
638
639 case "update_interval":
640 m_UpdateInterval = (int)value;
641 break;
642
643 default:
644 Output.Add(String.Format("Unknown parameter {0}.", args[1]));
645 return Output;
646 }
647
648 Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString())); 659 Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString()));
649
650 // Generate shared values
651 GenSunPos();
652
653 // When sun settings are updated, we should update all clients with new settings.
654 SunUpdateToAllClients();
655 } 660 }
656 661
657 return Output; 662 return Output;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
index 7186dd7..89087b1 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects
42 for (y = 0; y < map.Height; y++) 42 for (y = 0; y < map.Height; y++)
43 { 43 {
44 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; 44 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10;
45 double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2, Constants.RegionSize / 2, 50) * 0.01; 45 double spherFac = TerrainUtil.SphericalFactor(x, y, map.Width / 2, map.Height / 2, 50) * 0.01;
46 if (map[x, y] < spherFac) 46 if (map[x, y] < spherFac)
47 { 47 {
48 map[x, y] = spherFac; 48 map[x, y] = spherFac;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
index d78ade5..d5c77ec 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
@@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
67 { 67 {
68 using (Bitmap bitmap = new Bitmap(filename)) 68 using (Bitmap bitmap = new Bitmap(filename))
69 { 69 {
70 ITerrainChannel retval = new TerrainChannel(true); 70 ITerrainChannel retval = new TerrainChannel(w, h);
71 71
72 for (int x = 0; x < retval.Width; x++) 72 for (int x = 0; x < retval.Width; x++)
73 { 73 {
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
index 62d232e..be1fb24 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.IO; 29using System.IO;
30using OpenSim.Framework;
30using OpenSim.Region.Framework.Interfaces; 31using OpenSim.Region.Framework.Interfaces;
31using OpenSim.Region.Framework.Scenes; 32using OpenSim.Region.Framework.Scenes;
32 33
@@ -73,12 +74,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
73 public ITerrainChannel LoadFile(string filename) 74 public ITerrainChannel LoadFile(string filename)
74 { 75 {
75 FileInfo file = new FileInfo(filename); 76 FileInfo file = new FileInfo(filename);
76 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
77 ITerrainChannel retval = LoadStream(s);
78 77
79 s.Close(); 78 ITerrainChannel channel;
80 79
81 return retval; 80 using (FileStream s = file.Open(FileMode.Open, FileAccess.Read))
81 channel = LoadStream(s);
82
83 return channel;
82 } 84 }
83 85
84 public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight) 86 public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight)
@@ -86,153 +88,159 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
86 TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight); 88 TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight);
87 89
88 FileInfo file = new FileInfo(filename); 90 FileInfo file = new FileInfo(filename);
89 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
90 BinaryReader bs = new BinaryReader(s);
91 91
92 int currFileYOffset = fileHeight - 1; 92 using (FileStream s = file.Open(FileMode.Open, FileAccess.Read))
93 93 using (BinaryReader bs = new BinaryReader(s))
94 // if our region isn't on the first Y section of the areas to be landscaped, then
95 // advance to our section of the file
96 while (currFileYOffset > offsetY)
97 { 94 {
98 // read a whole strip of regions 95 int currFileYOffset = fileHeight - 1;
99 int heightsToRead = sectionHeight * (fileWidth * sectionWidth);
100 bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels
101 currFileYOffset--;
102 }
103 96
104 // got to the Y start offset within the file of our region 97 // if our region isn't on the first Y section of the areas to be landscaped, then
105 // so read the file bits associated with our region 98 // advance to our section of the file
106 int y; 99 while (currFileYOffset > offsetY)
107 // for each Y within our Y offset
108 for (y = sectionHeight - 1; y >= 0; y--)
109 {
110 int currFileXOffset = 0;
111
112 // if our region isn't the first X section of the areas to be landscaped, then
113 // advance the stream to the X start pos of our section in the file
114 // i.e. eat X upto where we start
115 while (currFileXOffset < offsetX)
116 { 100 {
117 bs.ReadBytes(sectionWidth * 13); 101 // read a whole strip of regions
118 currFileXOffset++; 102 int heightsToRead = sectionHeight * (fileWidth * sectionWidth);
103 bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels
104 currFileYOffset--;
119 } 105 }
120 106
121 // got to our X offset, so write our regions X line 107 // got to the Y start offset within the file of our region
122 int x; 108 // so read the file bits associated with our region
123 for (x = 0; x < sectionWidth; x++) 109 int y;
124 {
125 // Read a strip and continue
126 retval[x, y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
127 bs.ReadBytes(11);
128 }
129 // record that we wrote it
130 currFileXOffset++;
131 110
132 // if our region isn't the last X section of the areas to be landscaped, then 111 // for each Y within our Y offset
133 // advance the stream to the end of this Y column 112 for (y = sectionHeight - 1; y >= 0; y--)
134 while (currFileXOffset < fileWidth)
135 { 113 {
136 // eat the next regions x line 114 int currFileXOffset = 0;
137 bs.ReadBytes(sectionWidth * 13); //The 13 channels again 115
116 // if our region isn't the first X section of the areas to be landscaped, then
117 // advance the stream to the X start pos of our section in the file
118 // i.e. eat X upto where we start
119 while (currFileXOffset < offsetX)
120 {
121 bs.ReadBytes(sectionWidth * 13);
122 currFileXOffset++;
123 }
124
125 // got to our X offset, so write our regions X line
126 int x;
127 for (x = 0; x < sectionWidth; x++)
128 {
129 // Read a strip and continue
130 retval[x, y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
131 bs.ReadBytes(11);
132 }
133 // record that we wrote it
138 currFileXOffset++; 134 currFileXOffset++;
135
136 // if our region isn't the last X section of the areas to be landscaped, then
137 // advance the stream to the end of this Y column
138 while (currFileXOffset < fileWidth)
139 {
140 // eat the next regions x line
141 bs.ReadBytes(sectionWidth * 13); //The 13 channels again
142 currFileXOffset++;
143 }
139 } 144 }
140 } 145 }
141 146
142 bs.Close();
143 s.Close();
144
145 return retval; 147 return retval;
146 } 148 }
147 149
148 public ITerrainChannel LoadStream(Stream s) 150 public ITerrainChannel LoadStream(Stream s)
149 { 151 {
150 TerrainChannel retval = new TerrainChannel(); 152 // The raw format doesn't contain any dimension information.
153 // Guess the square dimensions by using the length of the raw file.
154 double dimension = Math.Sqrt((double)(s.Length / 13));
155 // Regions are always multiples of 256.
156 int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize);
157 if (trimmedDimension < Constants.RegionSize)
158 trimmedDimension = (int)Constants.RegionSize;
159
160 TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension);
151 161
152 BinaryReader bs = new BinaryReader(s); 162 using (BinaryReader bs = new BinaryReader(s))
153 int y;
154 for (y = 0; y < retval.Height; y++)
155 { 163 {
156 int x; 164 int y;
157 for (x = 0; x < retval.Width; x++) 165 for (y = 0; y < retval.Height; y++)
158 { 166 {
159 retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0); 167 int x;
160 bs.ReadBytes(11); // Advance the stream to next bytes. 168 for (x = 0; x < retval.Width; x++)
169 {
170 retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
171 bs.ReadBytes(11); // Advance the stream to next bytes.
172 }
161 } 173 }
162 } 174 }
163 175
164 bs.Close();
165
166 return retval; 176 return retval;
167 } 177 }
168 178
169 public void SaveFile(string filename, ITerrainChannel map) 179 public void SaveFile(string filename, ITerrainChannel map)
170 { 180 {
171 FileInfo file = new FileInfo(filename); 181 FileInfo file = new FileInfo(filename);
172 FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write);
173 SaveStream(s, map);
174 182
175 s.Close(); 183 using (FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write))
184 SaveStream(s, map);
176 } 185 }
177 186
178 public void SaveStream(Stream s, ITerrainChannel map) 187 public void SaveStream(Stream s, ITerrainChannel map)
179 { 188 {
180 BinaryWriter binStream = new BinaryWriter(s); 189 using (BinaryWriter binStream = new BinaryWriter(s))
181
182 // Output the calculated raw
183 for (int y = 0; y < map.Height; y++)
184 { 190 {
185 for (int x = 0; x < map.Width; x++) 191 // Output the calculated raw
192 for (int y = 0; y < map.Height; y++)
186 { 193 {
187 double t = map[x, (map.Height - 1) - y]; 194 for (int x = 0; x < map.Width; x++)
188 //if height is less than 0, set it to 0 as
189 //can't save -ve values in a LLRAW file
190 if (t < 0d)
191 { 195 {
192 t = 0d; 196 double t = map[x, (map.Height - 1) - y];
197 //if height is less than 0, set it to 0 as
198 //can't save -ve values in a LLRAW file
199 if (t < 0d)
200 {
201 t = 0d;
202 }
203
204 int index = 0;
205
206 // The lookup table is pre-sorted, so we either find an exact match or
207 // the next closest (smaller) match with a binary search
208 index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, (float)t));
209 if (index < 0)
210 index = ~index - 1;
211
212 index = LookupHeightTable[index].Index;
213
214 byte red = (byte) (index & 0xFF);
215 byte green = (byte) ((index >> 8) & 0xFF);
216 const byte blue = 20;
217 const byte alpha1 = 0;
218 const byte alpha2 = 0;
219 const byte alpha3 = 0;
220 const byte alpha4 = 0;
221 const byte alpha5 = 255;
222 const byte alpha6 = 255;
223 const byte alpha7 = 255;
224 const byte alpha8 = 255;
225 byte alpha9 = red;
226 byte alpha10 = green;
227
228 binStream.Write(red);
229 binStream.Write(green);
230 binStream.Write(blue);
231 binStream.Write(alpha1);
232 binStream.Write(alpha2);
233 binStream.Write(alpha3);
234 binStream.Write(alpha4);
235 binStream.Write(alpha5);
236 binStream.Write(alpha6);
237 binStream.Write(alpha7);
238 binStream.Write(alpha8);
239 binStream.Write(alpha9);
240 binStream.Write(alpha10);
193 } 241 }
194
195 int index = 0;
196
197 // The lookup table is pre-sorted, so we either find an exact match or
198 // the next closest (smaller) match with a binary search
199 index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, (float)t));
200 if (index < 0)
201 index = ~index - 1;
202
203 index = LookupHeightTable[index].Index;
204
205 byte red = (byte) (index & 0xFF);
206 byte green = (byte) ((index >> 8) & 0xFF);
207 const byte blue = 20;
208 const byte alpha1 = 0;
209 const byte alpha2 = 0;
210 const byte alpha3 = 0;
211 const byte alpha4 = 0;
212 const byte alpha5 = 255;
213 const byte alpha6 = 255;
214 const byte alpha7 = 255;
215 const byte alpha8 = 255;
216 byte alpha9 = red;
217 byte alpha10 = green;
218
219 binStream.Write(red);
220 binStream.Write(green);
221 binStream.Write(blue);
222 binStream.Write(alpha1);
223 binStream.Write(alpha2);
224 binStream.Write(alpha3);
225 binStream.Write(alpha4);
226 binStream.Write(alpha5);
227 binStream.Write(alpha6);
228 binStream.Write(alpha7);
229 binStream.Write(alpha8);
230 binStream.Write(alpha9);
231 binStream.Write(alpha10);
232 } 242 }
233 } 243 }
234
235 binStream.Close();
236 } 244 }
237 245
238 public string FileExtension 246 public string FileExtension
@@ -259,7 +267,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
259 public bool SupportsTileSave() 267 public bool SupportsTileSave()
260 { 268 {
261 return false; 269 return false;
262 } 270 }
263
264 } 271 }
265} 272} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
index 9fb7ef7..d467abb 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
@@ -25,7 +25,10 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
28using System.IO; 29using System.IO;
30
31using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces; 32using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
31 34
@@ -116,7 +119,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
116 119
117 public ITerrainChannel LoadStream(Stream s) 120 public ITerrainChannel LoadStream(Stream s)
118 { 121 {
119 TerrainChannel retval = new TerrainChannel(); 122 // The raw format doesn't contain any dimension information.
123 // Guess the square dimensions by using the length of the raw file.
124 double dimension = Math.Sqrt((double)(s.Length / 4));
125 // Regions are always multiples of 256.
126 int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize);
127 if (trimmedDimension < Constants.RegionSize)
128 trimmedDimension = (int)Constants.RegionSize;
129
130 TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension);
120 131
121 BinaryReader bs = new BinaryReader(s); 132 BinaryReader bs = new BinaryReader(s);
122 int y; 133 int y;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
index b5c7d33..219011e 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
@@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
65 bool eof = false; 65 bool eof = false;
66 66
67 int fileXPoints = 0; 67 int fileXPoints = 0;
68// int fileYPoints = 0; 68 int fileYPoints = 0;
69 69
70 // Terragen file 70 // Terragen file
71 while (eof == false) 71 while (eof == false)
@@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
75 { 75 {
76 case "SIZE": 76 case "SIZE":
77 fileXPoints = bs.ReadInt16() + 1; 77 fileXPoints = bs.ReadInt16() + 1;
78// fileYPoints = fileXPoints; 78 fileYPoints = fileXPoints;
79 bs.ReadInt16(); 79 bs.ReadInt16();
80 break; 80 break;
81 case "XPTS": 81 case "XPTS":
@@ -83,8 +83,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
83 bs.ReadInt16(); 83 bs.ReadInt16();
84 break; 84 break;
85 case "YPTS": 85 case "YPTS":
86// fileYPoints = bs.ReadInt16(); 86 fileYPoints = bs.ReadInt16();
87 bs.ReadInt16();
88 bs.ReadInt16(); 87 bs.ReadInt16();
89 break; 88 break;
90 case "ALTW": 89 case "ALTW":
@@ -138,7 +137,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
138 bs.ReadInt16(); 137 bs.ReadInt16();
139 } 138 }
140 139
141
142 break; 140 break;
143 default: 141 default:
144 bs.ReadInt32(); 142 bs.ReadInt32();
@@ -154,10 +152,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
154 152
155 public ITerrainChannel LoadStream(Stream s) 153 public ITerrainChannel LoadStream(Stream s)
156 { 154 {
157 155 // Set to default size
158 int w = (int)Constants.RegionSize; 156 int w = (int)Constants.RegionSize;
159 int h = (int)Constants.RegionSize; 157 int h = (int)Constants.RegionSize;
160 158
159 // create a dummy channel (in case data is bad)
161 TerrainChannel retval = new TerrainChannel(w, h); 160 TerrainChannel retval = new TerrainChannel(w, h);
162 161
163 BinaryReader bs = new BinaryReader(s); 162 BinaryReader bs = new BinaryReader(s);
@@ -165,8 +164,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
165 bool eof = false; 164 bool eof = false;
166 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") 165 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ")
167 { 166 {
168// int fileWidth = w;
169// int fileHeight = h;
170 167
171 // Terragen file 168 // Terragen file
172 while (eof == false) 169 while (eof == false)
@@ -175,31 +172,29 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
175 switch (tmp) 172 switch (tmp)
176 { 173 {
177 case "SIZE": 174 case "SIZE":
178// int sztmp = bs.ReadInt16() + 1; 175 w = bs.ReadInt16() + 1;
179// fileWidth = sztmp; 176 h = w;
180// fileHeight = sztmp;
181 bs.ReadInt16();
182 bs.ReadInt16(); 177 bs.ReadInt16();
183 break; 178 break;
184 case "XPTS": 179 case "XPTS":
185// fileWidth = bs.ReadInt16(); 180 w = bs.ReadInt16();
186 bs.ReadInt16();
187 bs.ReadInt16(); 181 bs.ReadInt16();
188 break; 182 break;
189 case "YPTS": 183 case "YPTS":
190// fileHeight = bs.ReadInt16(); 184 h = bs.ReadInt16();
191 bs.ReadInt16();
192 bs.ReadInt16(); 185 bs.ReadInt16();
193 break; 186 break;
194 case "ALTW": 187 case "ALTW":
195 eof = true; 188 eof = true;
196 Int16 heightScale = bs.ReadInt16(); 189 // create new channel of proper size (now that we know it)
197 Int16 baseHeight = bs.ReadInt16(); 190 retval = new TerrainChannel(w, h);
191 double heightScale = (double)bs.ReadInt16() / 65536.0;
192 double baseHeight = (double)bs.ReadInt16();
198 for (int y = 0; y < h; y++) 193 for (int y = 0; y < h; y++)
199 { 194 {
200 for (int x = 0; x < w; x++) 195 for (int x = 0; x < w; x++)
201 { 196 {
202 retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0; 197 retval[x, y] = baseHeight + (double)bs.ReadInt16() * heightScale;
203 } 198 }
204 } 199 }
205 break; 200 break;
@@ -209,9 +204,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
209 } 204 }
210 } 205 }
211 } 206 }
212
213 bs.Close(); 207 bs.Close();
214
215 return retval; 208 return retval;
216 } 209 }
217 210
@@ -257,17 +250,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
257 bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); 250 bs.Write(enc.GetBytes("TERRAGENTERRAIN "));
258 251
259 bs.Write(enc.GetBytes("SIZE")); 252 bs.Write(enc.GetBytes("SIZE"));
260 bs.Write(Convert.ToInt16(Constants.RegionSize)); 253 bs.Write(Convert.ToInt16(map.Width));
261 bs.Write(Convert.ToInt16(0)); // necessary padding 254 bs.Write(Convert.ToInt16(0)); // necessary padding
262 255
263 //The XPTS and YPTS chunks are not needed for square regions 256 //The XPTS and YPTS chunks are not needed for square regions
264 //but L3DT won't load the terrain file properly without them. 257 //but L3DT won't load the terrain file properly without them.
265 bs.Write(enc.GetBytes("XPTS")); 258 bs.Write(enc.GetBytes("XPTS"));
266 bs.Write(Convert.ToInt16(Constants.RegionSize)); 259 bs.Write(Convert.ToInt16(map.Width));
267 bs.Write(Convert.ToInt16(0)); // necessary padding 260 bs.Write(Convert.ToInt16(0)); // necessary padding
268 261
269 bs.Write(enc.GetBytes("YPTS")); 262 bs.Write(enc.GetBytes("YPTS"));
270 bs.Write(Convert.ToInt16(Constants.RegionSize)); 263 bs.Write(Convert.ToInt16(map.Height));
271 bs.Write(Convert.ToInt16(0)); // necessary padding 264 bs.Write(Convert.ToInt16(0)); // necessary padding
272 265
273 bs.Write(enc.GetBytes("SCAL")); 266 bs.Write(enc.GetBytes("SCAL"));
@@ -283,11 +276,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
283 bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min 276 bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min
284 bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point 277 bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point
285 278
279 double factor = 65536.0 / horizontalScale; // avoid computing this on each iteration
280
286 for (int y = 0; y < map.Height; y++) 281 for (int y = 0; y < map.Height; y++)
287 { 282 {
288 for (int x = 0; x < map.Width; x++) 283 for (int x = 0; x < map.Width; x++)
289 { 284 {
290 float elevation = (float)((map[x,y] - baseHeight) * 65536 ) / (float)horizontalScale; // see LoadStream for inverse 285 float elevation = (float)((map[x,y] - baseHeight) * factor); // see LoadStream for inverse
291 286
292 // clamp rounding issues 287 // clamp rounding issues
293 if (elevation > Int16.MaxValue) 288 if (elevation > Int16.MaxValue)
@@ -299,7 +294,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
299 } 294 }
300 } 295 }
301 296
302 //This is only necessary for older versions of Terragen. 297 //This is necessary for older versions of Terragen.
303 bs.Write(enc.GetBytes("EOF ")); 298 bs.Write(enc.GetBytes("EOF "));
304 299
305 bs.Close(); 300 bs.Close();
@@ -343,7 +338,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
343 if (BitConverter.IsLittleEndian == false) 338 if (BitConverter.IsLittleEndian == false)
344 { 339 {
345 byte[] tmp = new byte[4]; 340 byte[] tmp = new byte[4];
346 for (int i = 0; i < 4; i++) 341 for (int i = 3; i >= 0; i--)
347 { 342 {
348 tmp[i] = retVal[3 - i]; 343 tmp[i] = retVal[3 - i];
349 } 344 }
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
index 630473e..b6c635c 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
45 { 45 {
46 if (fillArea[x, y]) 46 if (fillArea[x, y])
47 { 47 {
48 double noise = TerrainUtil.PerlinNoise2D((double) x / Constants.RegionSize, (double) y / Constants.RegionSize, 8, 1.0); 48 double noise = TerrainUtil.PerlinNoise2D((double) x / map.Width, (double) y / map.Height, 8, 1.0);
49 49
50 map[x, y] += noise * strength; 50 map[x, y] += noise * strength;
51 } 51 }
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs
new file mode 100644
index 0000000..78a43db
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs
@@ -0,0 +1,60 @@
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
28using System;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain
32{
33 public interface ITerrainFeature
34 {
35 /// <summary>
36 /// Creates the feature.
37 /// </summary>
38 /// <returns>
39 /// Empty string if successful, otherwise error message.
40 /// </returns>
41 /// <param name='map'>
42 /// ITerrainChannel holding terrain data.
43 /// </param>
44 /// <param name='args'>
45 /// command-line arguments from console.
46 /// </param>
47 string CreateFeature(ITerrainChannel map, string[] args);
48
49 /// <summary>
50 /// Gets a string describing the usage.
51 /// </summary>
52 /// <returns>
53 /// A string describing parameters for creating the feature.
54 /// Format is "feature-name <arg1> <arg2> ..."
55 /// </returns>
56 string GetUsage();
57 }
58
59}
60
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs
new file mode 100644
index 0000000..0e0a0e4
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs
@@ -0,0 +1,77 @@
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
28using System;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain
32{
33 public interface ITerrainModifier
34 {
35 /// <summary>
36 /// Creates the feature.
37 /// </summary>
38 /// <returns>
39 /// Empty string if successful, otherwise error message.
40 /// </returns>
41 /// <param name='map'>
42 /// ITerrainChannel holding terrain data.
43 /// </param>
44 /// <param name='args'>
45 /// command-line arguments from console.
46 /// </param>
47 string ModifyTerrain(ITerrainChannel map, string[] args);
48
49 /// <summary>
50 /// Gets a string describing the usage.
51 /// </summary>
52 /// <returns>
53 /// A string describing parameters for creating the feature.
54 /// Format is "feature-name <arg1> <arg2> ..."
55 /// </returns>
56 string GetUsage();
57
58 /// <summary>
59 /// Apply the appropriate operation on the specified map, at (x, y).
60 /// </summary>
61 /// <param name='map'>
62 /// Map.
63 /// </param>
64 /// <param name='data'>
65 /// Data.
66 /// </param>
67 /// <param name='x'>
68 /// X.
69 /// </param>
70 /// <param name='y'>
71 /// Y.
72 /// </param>
73 double operate(double[,] map, TerrainModifierData data, int x, int y);
74 }
75
76}
77
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs
new file mode 100644
index 0000000..32f1de9
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs
@@ -0,0 +1,93 @@
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 */
27using System;
28
29using OpenSim.Region.CoreModules.World.Terrain;
30using OpenSim.Region.Framework.Interfaces;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
33{
34 public class FillModifier : TerrainModifier
35 {
36
37 public FillModifier(ITerrainModule module) : base(module)
38 {
39 }
40
41 public override string ModifyTerrain(ITerrainChannel map, string[] args)
42 {
43 string result;
44 if (args.Length < 3)
45 {
46 result = "Usage: " + GetUsage();
47 }
48 else
49 {
50 TerrainModifierData data;
51 result = this.parseParameters(args, out data);
52
53 // Context-specific validation
54 if (result == String.Empty)
55 {
56 if (data.shape == String.Empty)
57 {
58 data.shape = "rectangle";
59 data.x0 = 0;
60 data.y0 = 0;
61 data.dx = map.Width;
62 data.dy = map.Height;
63 }
64 }
65
66 // if it's all good, then do the work
67 if (result == String.Empty)
68 {
69 this.applyModification(map, data);
70 }
71 }
72
73 return result;
74 }
75
76 public override string GetUsage()
77 {
78 string val = "fill <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
79 + "\nSets all points within the specified range to the specified value.";
80 return val;
81 }
82
83 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
84 {
85 double factor = this.computeBevel(data, x, y);
86 double result = data.elevation - (data.elevation - data.bevelevation) * factor;
87 return result;
88 }
89
90 }
91
92}
93
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs
new file mode 100644
index 0000000..2ab4bcc
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs
@@ -0,0 +1,92 @@
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 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class LowerModifier : TerrainModifier
34 {
35 public LowerModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "lower <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
77 + "\nLowers all points within the specified range by the specified amount.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = map[x, y] - (data.elevation - (data.elevation - data.bevelevation) * factor);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs
new file mode 100644
index 0000000..0939c0a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs
@@ -0,0 +1,92 @@
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 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class MaxModifier : TerrainModifier
34 {
35 public MaxModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "max <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
77 + "\nEnsures that all points within the specified range are no higher than the specified value.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = Math.Min(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs
new file mode 100644
index 0000000..cbbccc0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs
@@ -0,0 +1,92 @@
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 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class MinModifier : TerrainModifier
34 {
35 public MinModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "min <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
77 + "\nEnsures that all points within the specified range are no lower than the specified value.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = Math.Max(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs
new file mode 100644
index 0000000..d6b95d0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs
@@ -0,0 +1,108 @@
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 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
33{
34 public class NoiseModifier : TerrainModifier
35 {
36 public NoiseModifier(ITerrainModule module) : base(module)
37 {
38 }
39
40 public override string ModifyTerrain(ITerrainChannel map, string[] args)
41 {
42 string result;
43 if (args.Length < 3)
44 {
45 result = "Usage: " + GetUsage();
46 }
47 else
48 {
49 TerrainModifierData data;
50 result = this.parseParameters(args, out data);
51
52 // Context-specific validation
53 if (result == String.Empty)
54 {
55 if (data.bevel == "taper")
56 {
57 if (data.bevelevation < 0.0 || data.bevelevation > 1.0)
58 {
59 result = String.Format("Taper must be 0.0 to 1.0: {0}", data.bevelevation);
60 }
61 }
62 else
63 {
64 data.bevelevation = 1.0f;
65 }
66
67 if (data.elevation < 0.0 || data.elevation > 1.0)
68 {
69 result = String.Format("Noise strength must be 0.0 to 1.0: {0}", data.elevation);
70 }
71
72 if (data.shape == String.Empty)
73 {
74 data.shape = "rectangle";
75 data.x0 = 0;
76 data.y0 = 0;
77 data.dx = map.Width;
78 data.dy = map.Height;
79 }
80 }
81
82 // if it's all good, then do the work
83 if (result == String.Empty)
84 {
85 this.applyModification(map, data);
86 }
87 }
88
89 return result;
90 }
91
92 public override string GetUsage()
93 {
94 string val = "noise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
95 + "\nAdds noise to all points within the specified range.";
96 return val;
97 }
98
99 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
100 {
101 double factor = this.computeBevel(data, x, y);
102 double noise = TerrainUtil.PerlinNoise2D((double)x / map.GetLength(0), (double)y / map.GetLength(1), 8, 1.0);
103 return map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor) * (noise - .5);
104 }
105
106 }
107
108}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs
new file mode 100644
index 0000000..35fb9d6
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs
@@ -0,0 +1,92 @@
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 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class RaiseModifier : TerrainModifier
34 {
35 public RaiseModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "raise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
77 + "\nRaises all points within the specified range by the specified amount.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs
new file mode 100644
index 0000000..9f8d5b2
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs
@@ -0,0 +1,131 @@
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 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class SmoothModifier : TerrainModifier
34 {
35 public SmoothModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.bevel == "taper")
55 {
56 if (data.bevelevation < 0.01 || data.bevelevation > 0.99)
57 {
58 result = String.Format("Taper must be 0.01 to 0.99: {0}", data.bevelevation);
59 }
60 }
61 else
62 {
63 data.bevelevation = 2.0f / 3.0f;
64 }
65
66 if (data.elevation < 0.0 || data.elevation > 1.0)
67 {
68 result = String.Format("Smoothing strength must be 0.0 to 1.0: {0}", data.elevation);
69 }
70
71 if (data.shape == String.Empty)
72 {
73 data.shape = "rectangle";
74 data.x0 = 0;
75 data.y0 = 0;
76 data.dx = map.Width;
77 data.dy = map.Height;
78 }
79 }
80
81 // if it's all good, then do the work
82 if (result == String.Empty)
83 {
84 this.applyModification(map, data);
85 }
86 }
87
88 return result;
89 }
90
91 public override string GetUsage()
92 {
93 string val = "smooth <strength> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<fraction>]"
94 + "\nSmooths all points within the specified range using a simple averaging algorithm.";
95 return val;
96 }
97
98 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
99 {
100 double[] scale = new double[3];
101 scale[0] = data.elevation;
102 scale[1] = ((1.0 - scale[0]) * data.bevelevation) / 8.0;
103 scale[2] = ((1.0 - scale[0]) * (1.0 - data.bevelevation)) / 16.0;
104 int xMax = map.GetLength(0);
105 int yMax = map.GetLength(1);
106 double result;
107 if ((x == 0) || (y == 0) || (x == (xMax - 1)) || (y == (yMax - 1)))
108 {
109 result = map[x, y];
110 }
111 else
112 {
113 result = 0.0;
114 for(int yPos = (y - 2); yPos < (y + 3); yPos++)
115 {
116 int yVal = (yPos <= 0) ? 0 : ((yPos < yMax) ? yPos : yMax - 1);
117 for(int xPos = (x - 2); xPos < (x + 3); xPos++)
118 {
119 int xVal = (xPos <= 0) ? 0 : ((xPos < xMax) ? xPos : xMax - 1);
120 int dist = Math.Max(Math.Abs(x - xVal), Math.Abs(y - yVal));
121 result += map[xVal, yVal] * scale[dist];
122 }
123 }
124 }
125 return result;
126 }
127
128 }
129
130}
131
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
index 989b7d8..e7df3f8 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
53 z *= z; 53 z *= z;
54 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); 54 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry));
55 55
56 double noise = TerrainUtil.PerlinNoise2D(x / (double) Constants.RegionSize, y / (double) Constants.RegionSize, 8, 1.0); 56 double noise = TerrainUtil.PerlinNoise2D(x / (double) map.Width, y / (double) map.Height, 8, 1.0);
57 57
58 if (z > 0.0) 58 if (z > 0.0)
59 map[x, y] += noise * z * duration; 59 map[x, y] += noise * z * duration;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs
new file mode 100644
index 0000000..7ebd08e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs
@@ -0,0 +1,378 @@
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 */
27using System;
28using System.Reflection;
29using log4net;
30
31using OpenSim.Region.Framework.Interfaces;
32
33namespace OpenSim.Region.CoreModules.World.Terrain
34{
35 public abstract class TerrainModifier : ITerrainModifier
36 {
37 protected ITerrainModule m_module;
38 protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39
40 protected TerrainModifier(ITerrainModule module)
41 {
42 m_module = module;
43 }
44
45 public abstract string ModifyTerrain(ITerrainChannel map, string[] args);
46
47 public abstract string GetUsage();
48
49 public abstract double operate(double[,] map, TerrainModifierData data, int x, int y);
50
51 protected String parseParameters(string[] args, out TerrainModifierData data)
52 {
53 string val;
54 string arg;
55 string result;
56 data = new TerrainModifierData();
57 data.shape = String.Empty;
58 data.bevel = String.Empty;
59 data.dx = 0;
60 data.dy = 0;
61 if (args.Length < 4)
62 {
63 result = "Usage: " + GetUsage();
64 }
65 else
66 {
67 result = this.parseFloat(args[3], out data.elevation);
68 }
69 if (result == String.Empty)
70 {
71 int index = 3;
72 while(++index < args.Length && result == String.Empty)
73 {
74 arg = args[index];
75 // check for shape
76 if (arg.StartsWith("-rec=") || arg.StartsWith("-ell="))
77 {
78 if (data.shape != String.Empty)
79 {
80 result = "Only 1 '-rec' or '-ell' parameter is permitted.";
81 }
82 else
83 {
84 data.shape = arg.StartsWith("-ell=") ? "ellipse" : "rectangle";
85 val = arg.Substring(arg.IndexOf("=") + 1);
86 string[] coords = val.Split(new char[] {','});
87 if ((coords.Length < 3) || (coords.Length > 4))
88 {
89 result = String.Format("Bad format for shape parameter {0}", arg);
90 }
91 else
92 {
93 result = this.parseInt(coords[0], out data.x0);
94 if (result == String.Empty)
95 {
96 result = this.parseInt(coords[1], out data.y0);
97 }
98 if (result == String.Empty)
99 {
100 result = this.parseInt(coords[2], out data.dx);
101 }
102 if (result == String.Empty)
103 {
104 if (coords.Length == 4)
105 {
106 result = this.parseInt(coords[3], out data.dy);
107 }
108 else
109 {
110 data.dy = data.dx;
111 }
112 }
113 if (result == String.Empty)
114 {
115 if ((data.dx <= 0) || (data.dy <= 0))
116 {
117 result = "Shape sizes must be positive integers";
118 }
119 }
120 else
121 {
122 result = String.Format("Bad value in shape parameters {0}", arg);
123 }
124 }
125 }
126 }
127 else if (arg.StartsWith("-taper="))
128 {
129 if (data.bevel != String.Empty)
130 {
131 result = "Only 1 '-taper' parameter is permitted.";
132 }
133 else
134 {
135 data.bevel = "taper";
136 val = arg.Substring(arg.IndexOf("=") + 1);
137 result = this.parseFloat(val, out data.bevelevation);
138 if (result != String.Empty)
139 {
140 result = String.Format("Bad format for taper parameter {0}", arg);
141 }
142 }
143 }
144 else
145 {
146 result = String.Format("Unrecognized parameter {0}", arg);
147 }
148 }
149 }
150 return result;
151 }
152
153 protected string parseFloat(String s, out float f)
154 {
155 string result;
156 double d;
157 if (Double.TryParse(s, out d))
158 {
159 try
160 {
161 f = (float)d;
162 result = String.Empty;
163 }
164 catch(InvalidCastException)
165 {
166 result = String.Format("{0} is invalid", s);
167 f = -1.0f;
168 }
169 }
170 else
171 {
172 f = -1.0f;
173 result = String.Format("{0} is invalid", s);
174 }
175 return result;
176 }
177
178 protected string parseInt(String s, out int i)
179 {
180 string result;
181 if (Int32.TryParse(s, out i))
182 {
183 result = String.Empty;
184 }
185 else
186 {
187 result = String.Format("{0} is invalid", s);
188 }
189 return result;
190 }
191
192 protected void applyModification(ITerrainChannel map, TerrainModifierData data)
193 {
194 bool[,] mask;
195 int xMax;
196 int yMax;
197 int xMid;
198 int yMid;
199 if (data.shape == "ellipse")
200 {
201 mask = this.ellipticalMask(data.dx, data.dy);
202 xMax = mask.GetLength(0);
203 yMax = mask.GetLength(1);
204 xMid = xMax / 2 + xMax % 2;
205 yMid = yMax / 2 + yMax % 2;
206 }
207 else
208 {
209 mask = this.rectangularMask(data.dx, data.dy);
210 xMax = mask.GetLength(0);
211 yMax = mask.GetLength(1);
212 xMid = 0;
213 yMid = 0;
214 }
215// m_log.DebugFormat("Apply {0} mask {1}x{2} @ {3},{4}", data.shape, xMax, yMax, xMid, yMid);
216 double[,] buffer = map.GetDoubles();
217 int yDim = yMax;
218 while(--yDim >= 0)
219 {
220 int yPos = data.y0 + yDim - yMid;
221 if ((yPos >= 0) && (yPos < map.Height))
222 {
223 int xDim = xMax;
224 while(--xDim >= 0)
225 {
226 int xPos = data.x0 + xDim - xMid;
227 if ((xPos >= 0) && (xPos < map.Width) && (mask[xDim, yDim]))
228 {
229 double endElevation = this.operate(buffer, data, xPos, yPos);
230 map[xPos, yPos] = endElevation;
231 }
232 }
233 }
234 }
235 }
236
237 protected double computeBevel(TerrainModifierData data, int x, int y)
238 {
239 int deltaX;
240 int deltaY;
241 int xMax;
242 int yMax;
243 double factor;
244 if (data.bevel == "taper")
245 {
246 if (data.shape == "ellipse")
247 {
248 deltaX = x - data.x0;
249 deltaY = y - data.y0;
250 xMax = data.dx;
251 yMax = data.dy;
252 factor = (double)((deltaX * deltaX) + (deltaY * deltaY));
253 factor /= ((xMax * xMax) + (yMax * yMax));
254 }
255 else
256 {
257 // pyramid
258 xMax = data.dx / 2 + data.dx % 2;
259 yMax = data.dy / 2 + data.dy % 2;
260 deltaX = Math.Abs(data.x0 + xMax - x);
261 deltaY = Math.Abs(data.y0 + yMax - y);
262 factor = Math.Max(((double)(deltaY) / yMax), ((double)(deltaX) / xMax));
263 }
264 }
265 else
266 {
267 factor = 0.0;
268 }
269 return factor;
270 }
271
272 private bool[,] rectangularMask(int xSize, int ySize)
273 {
274 bool[,] mask = new bool[xSize, ySize];
275 int yPos = ySize;
276 while(--yPos >= 0)
277 {
278 int xPos = xSize;
279 while(--xPos >= 0)
280 {
281 mask[xPos, yPos] = true;
282 }
283 }
284 return mask;
285 }
286
287 /*
288 * Fast ellipse-based derivative of Bresenham algorithm.
289 * https://web.archive.org/web/20120225095359/http://homepage.smc.edu/kennedy_john/belipse.pdf
290 */
291 private bool[,] ellipticalMask(int xRadius, int yRadius)
292 {
293 long twoASquared = 2L * xRadius * xRadius;
294 long twoBSquared = 2L * yRadius * yRadius;
295
296 bool[,] mask = new bool[2 * xRadius + 1, 2 * yRadius + 1];
297
298 long ellipseError = 0L;
299 long stoppingX = twoBSquared * xRadius;
300 long stoppingY = 0L;
301 long xChange = yRadius * yRadius * (1L - 2L * xRadius);
302 long yChange = xRadius * xRadius;
303
304 int xPos = xRadius;
305 int yPos = 0;
306
307 // first set of points
308 while(stoppingX >= stoppingY)
309 {
310 int yUpper = yRadius + yPos;
311 int yLower = yRadius - yPos;
312 // fill in the mask
313 int xNow = xPos;
314 while(xNow >= 0)
315 {
316 mask[xRadius + xNow, yUpper] = true;
317 mask[xRadius - xNow, yUpper] = true;
318 mask[xRadius + xNow, yLower] = true;
319 mask[xRadius - xNow, yLower] = true;
320 --xNow;
321 }
322 yPos++;
323 stoppingY += twoASquared;
324 ellipseError += yChange;
325 yChange += twoASquared;
326 if ((2L * ellipseError + xChange) > 0L)
327 {
328 xPos--;
329 stoppingX -= twoBSquared;
330 ellipseError += xChange;
331 xChange += twoBSquared;
332 }
333 }
334
335 // second set of points
336 xPos = 0;
337 yPos = yRadius;
338 xChange = yRadius * yRadius;
339 yChange = xRadius * xRadius * (1L - 2L * yRadius);
340
341 ellipseError = 0L;
342 stoppingX = 0L;
343 stoppingY = twoASquared * yRadius;
344
345 while(stoppingX <= stoppingY)
346 {
347 int xUpper = xRadius + xPos;
348 int xLower = xRadius - xPos;
349 // fill in the mask
350 int yNow = yPos;
351 while(yNow >= 0)
352 {
353 mask[xUpper, yRadius + yNow] = true;
354 mask[xUpper, yRadius - yNow] = true;
355 mask[xLower, yRadius + yNow] = true;
356 mask[xLower, yRadius - yNow] = true;
357 --yNow;
358 }
359 xPos++;
360 stoppingX += twoBSquared;
361 ellipseError += xChange;
362 xChange += twoBSquared;
363 if ((2L * ellipseError + yChange) > 0L)
364 {
365 yPos--;
366 stoppingY -= twoASquared;
367 ellipseError += yChange;
368 yChange += twoASquared;
369 }
370 }
371 return mask;
372 }
373
374
375 }
376
377}
378
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs
new file mode 100644
index 0000000..4e0f8d7
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs
@@ -0,0 +1,17 @@
1using System;
2
3namespace OpenSim.Region.CoreModules.World.Terrain
4{
5 public struct TerrainModifierData
6 {
7 public float elevation;
8 public string shape;
9 public int x0;
10 public int y0;
11 public int dx;
12 public int dy;
13 public string bevel;
14 public float bevelevation;
15 }
16}
17
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index fd30c46..932652c 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -24,19 +24,24 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27
28using System; 27using System;
29using System.Collections.Generic; 28using System.Collections.Generic;
30using System.IO; 29using System.IO;
31using System.Reflection; 30using System.Reflection;
32using System.Net; 31using System.Net;
32
33using log4net; 33using log4net;
34using Nini.Config; 34using Nini.Config;
35
35using OpenMetaverse; 36using OpenMetaverse;
36using Mono.Addins; 37using Mono.Addins;
38
39using OpenSim.Data;
37using OpenSim.Framework; 40using OpenSim.Framework;
41using OpenSim.Framework.Console;
38using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 42using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
39using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; 43using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
44using OpenSim.Region.CoreModules.World.Terrain.Modifiers;
40using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; 45using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes;
41using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; 46using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
42using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
@@ -70,26 +75,112 @@ namespace OpenSim.Region.CoreModules.World.Terrain
70 #endregion 75 #endregion
71 76
72 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
73
74 private readonly Commander m_commander = new Commander("terrain");
75 78
79#pragma warning disable 414
80 private static readonly string LogHeader = "[TERRAIN MODULE]";
81#pragma warning restore 414
82
83 private readonly Commander m_commander = new Commander("terrain");
76 private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = 84 private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects =
77 new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>(); 85 new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>();
78
79 private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); 86 private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>();
80
81 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = 87 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
82 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); 88 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
83
84 private ITerrainChannel m_channel;
85 private Dictionary<string, ITerrainEffect> m_plugineffects; 89 private Dictionary<string, ITerrainEffect> m_plugineffects;
90 private Dictionary<string, ITerrainModifier> m_modifyOperations =
91 new Dictionary<string, ITerrainModifier>();
92 private ITerrainChannel m_channel;
86 private ITerrainChannel m_revert; 93 private ITerrainChannel m_revert;
87 private Scene m_scene; 94 private Scene m_scene;
88 private volatile bool m_tainted; 95 private volatile bool m_tainted;
89 private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); 96 private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5);
90
91 private String m_InitialTerrain = "pinhead-island"; 97 private String m_InitialTerrain = "pinhead-island";
92 98
99 // If true, send terrain patch updates to clients based on their view distance
100 private bool m_sendTerrainUpdatesByViewDistance = true;
101
102 // Class to keep the per client collection of terrain patches that must be sent.
103 // A patch is set to 'true' meaning it should be sent to the client. Once the
104 // patch packet is queued to the client, the bit for that patch is set to 'false'.
105 private class PatchUpdates
106 {
107 private bool[,] updated; // for each patch, whether it needs to be sent to this client
108 private int updateCount; // number of patches that need to be sent
109 public ScenePresence Presence; // a reference to the client to send to
110 public TerrainData Terrain; // reference to the underlying terrain
111 public PatchUpdates(TerrainData terrData, ScenePresence pPresence)
112 {
113 updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize];
114 updateCount = 0;
115 Presence = pPresence;
116 Terrain = terrData;
117 // Initially, send all patches to the client
118 SetAll(true);
119 }
120 // Returns 'true' if there are any patches marked for sending
121 public bool HasUpdates()
122 {
123 return (updateCount > 0);
124 }
125
126 public void SetByXY(int x, int y, bool state)
127 {
128 this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
129 }
130
131 public bool GetByPatch(int patchX, int patchY)
132 {
133 return updated[patchX, patchY];
134 }
135
136 public void SetByPatch(int patchX, int patchY, bool state)
137 {
138 bool prevState = updated[patchX, patchY];
139 if (!prevState && state)
140 updateCount++;
141 if (prevState && !state)
142 updateCount--;
143 updated[patchX, patchY] = state;
144 }
145
146 public void SetAll(bool state)
147 {
148 updateCount = 0;
149 for(int xx = 0; xx < updated.GetLength(0); xx++)
150 for(int yy = 0; yy < updated.GetLength(1); yy++)
151 updated[xx, yy] = state;
152 if (state)
153 updateCount = updated.GetLength(0) * updated.GetLength(1);
154 }
155 // Logically OR's the terrain data's patch taint map into this client's update map.
156 public void SetAll(TerrainData terrData)
157 {
158 if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize)
159 || updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize))
160 {
161 throw new Exception(
162 String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>",
163 LogHeader, updated.GetLength(0), updated.GetLength(1),
164 terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
165 );
166 }
167 for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
168 {
169 for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
170 {
171 // Only set tainted. The patch bit may be set if the patch was to be sent later.
172 if (terrData.IsTaintedAt(xx, yy, false))
173 {
174 this.SetByXY(xx, yy, true);
175 }
176 }
177 }
178 }
179 }
180
181 // The flags of which terrain patches to send for each of the ScenePresence's
182 private Dictionary<UUID, PatchUpdates> m_perClientPatchUpdates = new Dictionary<UUID, PatchUpdates>();
183
93 /// <summary> 184 /// <summary>
94 /// Human readable list of terrain file extensions that are supported. 185 /// Human readable list of terrain file extensions that are supported.
95 /// </summary> 186 /// </summary>
@@ -100,8 +191,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
100 191
101 #region ICommandableModule Members 192 #region ICommandableModule Members
102 193
103 public ICommander CommandInterface 194 public ICommander CommandInterface {
104 {
105 get { return m_commander; } 195 get { return m_commander; }
106 } 196 }
107 197
@@ -118,7 +208,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
118 { 208 {
119 IConfig terrainConfig = config.Configs["Terrain"]; 209 IConfig terrainConfig = config.Configs["Terrain"];
120 if (terrainConfig != null) 210 if (terrainConfig != null)
211 {
121 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 212 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
213 m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance);
214 }
122 } 215 }
123 216
124 public void AddRegion(Scene scene) 217 public void AddRegion(Scene scene)
@@ -126,26 +219,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
126 m_scene = scene; 219 m_scene = scene;
127 220
128 // Install terrain module in the simulator 221 // Install terrain module in the simulator
129 lock (m_scene) 222 lock(m_scene)
130 { 223 {
131 if (m_scene.Heightmap == null) 224 if (m_scene.Heightmap == null)
132 { 225 {
133 m_channel = new TerrainChannel(m_InitialTerrain); 226 m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX,
227 (int)m_scene.RegionInfo.RegionSizeY,
228 (int)m_scene.RegionInfo.RegionSizeZ);
134 m_scene.Heightmap = m_channel; 229 m_scene.Heightmap = m_channel;
135 m_revert = new TerrainChannel();
136 UpdateRevertMap(); 230 UpdateRevertMap();
137 } 231 }
138 else 232 else
139 { 233 {
140 m_channel = m_scene.Heightmap; 234 m_channel = m_scene.Heightmap;
141 m_revert = new TerrainChannel();
142 UpdateRevertMap(); 235 UpdateRevertMap();
143 } 236 }
144 237
145 m_scene.RegisterModuleInterface<ITerrainModule>(this); 238 m_scene.RegisterModuleInterface<ITerrainModule>(this);
146 m_scene.EventManager.OnNewClient += EventManager_OnNewClient; 239 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
240 m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed;
147 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; 241 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
148 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; 242 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick;
243 m_scene.EventManager.OnFrame += EventManager_OnFrame;
149 } 244 }
150 245
151 InstallDefaultEffects(); 246 InstallDefaultEffects();
@@ -156,7 +251,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
156 string supportedFilesSeparatorForTileSave = ""; 251 string supportedFilesSeparatorForTileSave = "";
157 252
158 m_supportFileExtensionsForTileSave = ""; 253 m_supportFileExtensionsForTileSave = "";
159 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 254 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
160 { 255 {
161 m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; 256 m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")";
162 supportedFilesSeparator = ", "; 257 supportedFilesSeparator = ", ";
@@ -179,13 +274,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
179 274
180 public void RemoveRegion(Scene scene) 275 public void RemoveRegion(Scene scene)
181 { 276 {
182 lock (m_scene) 277 lock(m_scene)
183 { 278 {
184 // remove the commands 279 // remove the commands
185 m_scene.UnregisterModuleCommander(m_commander.Name); 280 m_scene.UnregisterModuleCommander(m_commander.Name);
186 // remove the event-handlers 281 // remove the event-handlers
282 m_scene.EventManager.OnFrame -= EventManager_OnFrame;
187 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; 283 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick;
188 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; 284 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole;
285 m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed;
189 m_scene.EventManager.OnNewClient -= EventManager_OnNewClient; 286 m_scene.EventManager.OnNewClient -= EventManager_OnNewClient;
190 // remove the interface 287 // remove the interface
191 m_scene.UnregisterModuleInterface<ITerrainModule>(this); 288 m_scene.UnregisterModuleInterface<ITerrainModule>(this);
@@ -196,13 +293,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
196 { 293 {
197 } 294 }
198 295
199 public Type ReplaceableInterface 296 public Type ReplaceableInterface {
200 {
201 get { return null; } 297 get { return null; }
202 } 298 }
203 299
204 public string Name 300 public string Name {
205 {
206 get { return "TerrainModule"; } 301 get { return "TerrainModule"; }
207 } 302 }
208 303
@@ -221,47 +316,46 @@ namespace OpenSim.Region.CoreModules.World.Terrain
221 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> 316 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
222 public void LoadFromFile(string filename) 317 public void LoadFromFile(string filename)
223 { 318 {
224 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 319 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
225 { 320 {
226 if (filename.EndsWith(loader.Key)) 321 if (filename.EndsWith(loader.Key))
227 { 322 {
228 lock (m_scene) 323 lock(m_scene)
229 { 324 {
230 try 325 try
231 { 326 {
232 ITerrainChannel channel = loader.Value.LoadFile(filename); 327 ITerrainChannel channel = loader.Value.LoadFile(filename);
233 if (channel.Width != Constants.RegionSize || channel.Height != Constants.RegionSize) 328 if (channel.Width != m_scene.RegionInfo.RegionSizeX || channel.Height != m_scene.RegionInfo.RegionSizeY)
234 { 329 {
235 // TerrainChannel expects a RegionSize x RegionSize map, currently 330 // TerrainChannel expects a RegionSize x RegionSize map, currently
236 throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", 331 throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}",
237 Constants.RegionSize, Constants.RegionSize)); 332 m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY));
238 } 333 }
239 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); 334 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height);
240 m_scene.Heightmap = channel; 335 m_scene.Heightmap = channel;
241 m_channel = channel; 336 m_channel = channel;
242 UpdateRevertMap(); 337 UpdateRevertMap();
243 } 338 }
244 catch (NotImplementedException) 339 catch(NotImplementedException)
245 { 340 {
246 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + 341 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
247 " parser does not support file loading. (May be save only)"); 342 " parser does not support file loading. (May be save only)");
248 throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); 343 throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value));
249 } 344 }
250 catch (FileNotFoundException) 345 catch(FileNotFoundException)
251 { 346 {
252 m_log.Error( 347 m_log.Error(
253 "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); 348 "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)");
254 throw new TerrainException( 349 throw new TerrainException(
255 String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); 350 String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename));
256 } 351 }
257 catch (ArgumentException e) 352 catch(ArgumentException e)
258 { 353 {
259 m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); 354 m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message);
260 throw new TerrainException( 355 throw new TerrainException(
261 String.Format("Unable to load heightmap: {0}", e.Message)); 356 String.Format("Unable to load heightmap: {0}", e.Message));
262 } 357 }
263 } 358 }
264 CheckForTerrainUpdates();
265 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); 359 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
266 return; 360 return;
267 } 361 }
@@ -279,7 +373,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
279 { 373 {
280 try 374 try
281 { 375 {
282 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 376 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
283 { 377 {
284 if (filename.EndsWith(loader.Key)) 378 if (filename.EndsWith(loader.Key))
285 { 379 {
@@ -289,7 +383,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
289 } 383 }
290 } 384 }
291 } 385 }
292 catch (IOException ioe) 386 catch(IOException ioe)
293 { 387 {
294 m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); 388 m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message));
295 } 389 }
@@ -309,27 +403,32 @@ namespace OpenSim.Region.CoreModules.World.Terrain
309 LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); 403 LoadFromStream(filename, URIFetch(pathToTerrainHeightmap));
310 } 404 }
311 405
406 public void LoadFromStream(string filename, Stream stream)
407 {
408 LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream);
409 }
410
312 /// <summary> 411 /// <summary>
313 /// Loads a terrain file from a stream and installs it in the scene. 412 /// Loads a terrain file from a stream and installs it in the scene.
314 /// </summary> 413 /// </summary>
315 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> 414 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
316 /// <param name="stream"></param> 415 /// <param name="stream"></param>
317 public void LoadFromStream(string filename, Stream stream) 416 public void LoadFromStream(string filename, Vector3 displacement,
417 float radianRotation, Vector2 rotationDisplacement, Stream stream)
318 { 418 {
319 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 419 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
320 { 420 {
321 if (filename.EndsWith(loader.Key)) 421 if (filename.EndsWith(loader.Key))
322 { 422 {
323 lock (m_scene) 423 lock(m_scene)
324 { 424 {
325 try 425 try
326 { 426 {
327 ITerrainChannel channel = loader.Value.LoadStream(stream); 427 ITerrainChannel channel = loader.Value.LoadStream(stream);
328 m_scene.Heightmap = channel; 428 m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
329 m_channel = channel;
330 UpdateRevertMap(); 429 UpdateRevertMap();
331 } 430 }
332 catch (NotImplementedException) 431 catch(NotImplementedException)
333 { 432 {
334 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + 433 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
335 " parser does not support file loading. (May be save only)"); 434 " parser does not support file loading. (May be save only)");
@@ -337,7 +436,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
337 } 436 }
338 } 437 }
339 438
340 CheckForTerrainUpdates();
341 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); 439 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
342 return; 440 return;
343 } 441 }
@@ -390,7 +488,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
390 { 488 {
391 try 489 try
392 { 490 {
393 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 491 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
394 { 492 {
395 if (filename.EndsWith(loader.Key)) 493 if (filename.EndsWith(loader.Key))
396 { 494 {
@@ -399,18 +497,56 @@ namespace OpenSim.Region.CoreModules.World.Terrain
399 } 497 }
400 } 498 }
401 } 499 }
402 catch (NotImplementedException) 500 catch(NotImplementedException)
403 { 501 {
404 m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); 502 m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented.");
405 throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); 503 throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented"));
406 } 504 }
407 } 505 }
408 506
409 public void TaintTerrain () 507 // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
508 // ITerrainModule.TaintTerrain()
509 public void TaintTerrain()
410 { 510 {
411 CheckForTerrainUpdates(); 511 lock(m_perClientPatchUpdates)
512 {
513 // Set the flags for all clients so the tainted patches will be sent out
514 foreach(PatchUpdates pups in m_perClientPatchUpdates.Values)
515 {
516 pups.SetAll(m_scene.Heightmap.GetTerrainData());
517 }
518 }
412 } 519 }
413 520
521 // ITerrainModule.PushTerrain()
522 public void PushTerrain(IClientAPI pClient)
523 {
524 // If view distance based, set the modified patch bits and the frame event will send the updates
525 if (m_sendTerrainUpdatesByViewDistance)
526 {
527 ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
528 if (presence != null)
529 {
530 lock(m_perClientPatchUpdates)
531 {
532 PatchUpdates pups;
533 if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups))
534 {
535 // There is a ScenePresence without a send patch map. Create one.
536 pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence);
537 m_perClientPatchUpdates.Add(presence.UUID, pups);
538 }
539 // By setting all to modified, the next update tick will send the patches
540 pups.SetAll(true);
541 }
542 }
543 }
544 else
545 {
546 // The traditional way is to call into the protocol stack to send them all.
547 pClient.SendLayerData(new float[10]);
548 }
549 }
414 #region Plugin Loading Methods 550 #region Plugin Loading Methods
415 551
416 private void LoadPlugins() 552 private void LoadPlugins()
@@ -418,13 +554,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
418 m_plugineffects = new Dictionary<string, ITerrainEffect>(); 554 m_plugineffects = new Dictionary<string, ITerrainEffect>();
419 LoadPlugins(Assembly.GetCallingAssembly()); 555 LoadPlugins(Assembly.GetCallingAssembly());
420 string plugineffectsPath = "Terrain"; 556 string plugineffectsPath = "Terrain";
421 557
422 // Load the files in the Terrain/ dir 558 // Load the files in the Terrain/ dir
423 if (!Directory.Exists(plugineffectsPath)) 559 if (!Directory.Exists(plugineffectsPath))
424 return; 560 return;
425 561
426 string[] files = Directory.GetFiles(plugineffectsPath); 562 string[] files = Directory.GetFiles(plugineffectsPath);
427 foreach (string file in files) 563 foreach(string file in files)
428 { 564 {
429 m_log.Info("Loading effects in " + file); 565 m_log.Info("Loading effects in " + file);
430 try 566 try
@@ -432,7 +568,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
432 Assembly library = Assembly.LoadFrom(file); 568 Assembly library = Assembly.LoadFrom(file);
433 LoadPlugins(library); 569 LoadPlugins(library);
434 } 570 }
435 catch (BadImageFormatException) 571 catch(BadImageFormatException)
436 { 572 {
437 } 573 }
438 } 574 }
@@ -440,7 +576,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
440 576
441 private void LoadPlugins(Assembly library) 577 private void LoadPlugins(Assembly library)
442 { 578 {
443 foreach (Type pluginType in library.GetTypes()) 579 foreach(Type pluginType in library.GetTypes())
444 { 580 {
445 try 581 try
446 { 582 {
@@ -462,7 +598,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
462 m_log.Info("L ... " + typeName); 598 m_log.Info("L ... " + typeName);
463 } 599 }
464 } 600 }
465 catch (AmbiguousMatchException) 601 catch(AmbiguousMatchException)
466 { 602 {
467 } 603 }
468 } 604 }
@@ -470,7 +606,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
470 606
471 public void InstallPlugin(string pluginName, ITerrainEffect effect) 607 public void InstallPlugin(string pluginName, ITerrainEffect effect)
472 { 608 {
473 lock (m_plugineffects) 609 lock(m_plugineffects)
474 { 610 {
475 if (!m_plugineffects.ContainsKey(pluginName)) 611 if (!m_plugineffects.ContainsKey(pluginName))
476 { 612 {
@@ -513,6 +649,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
513 m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); 649 m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea();
514 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); 650 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert);
515 651
652 // Terrain Modifier operations
653 m_modifyOperations["min"] = new MinModifier(this);
654 m_modifyOperations["max"] = new MaxModifier(this);
655 m_modifyOperations["raise"] = new RaiseModifier(this);
656 m_modifyOperations["lower"] = new LowerModifier(this);
657 m_modifyOperations["fill"] = new FillModifier(this);
658 m_modifyOperations["smooth"] = new SmoothModifier(this);
659 m_modifyOperations["noise"] = new NoiseModifier(this);
660
516 // Filesystem load/save loaders 661 // Filesystem load/save loaders
517 m_loaders[".r32"] = new RAW32(); 662 m_loaders[".r32"] = new RAW32();
518 m_loaders[".f32"] = m_loaders[".r32"]; 663 m_loaders[".f32"] = m_loaders[".r32"];
@@ -532,6 +677,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
532 /// </summary> 677 /// </summary>
533 public void UpdateRevertMap() 678 public void UpdateRevertMap()
534 { 679 {
680 /*
535 int x; 681 int x;
536 for (x = 0; x < m_channel.Width; x++) 682 for (x = 0; x < m_channel.Width; x++)
537 { 683 {
@@ -541,6 +687,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
541 m_revert[x, y] = m_channel[x, y]; 687 m_revert[x, y] = m_channel[x, y];
542 } 688 }
543 } 689 }
690 */
691 m_revert = m_channel.MakeCopy();
544 } 692 }
545 693
546 /// <summary> 694 /// <summary>
@@ -553,22 +701,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
553 /// <param name="fileStartY">Where to begin our slice</param> 701 /// <param name="fileStartY">Where to begin our slice</param>
554 public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) 702 public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY)
555 { 703 {
556 int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX; 704 int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX;
557 int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY; 705 int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY;
558 706
559 if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) 707 if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight)
560 { 708 {
561 // this region is included in the tile request 709 // this region is included in the tile request
562 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 710 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
563 { 711 {
564 if (filename.EndsWith(loader.Key)) 712 if (filename.EndsWith(loader.Key))
565 { 713 {
566 lock (m_scene) 714 lock(m_scene)
567 { 715 {
568 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, 716 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
569 fileWidth, fileHeight, 717 fileWidth, fileHeight,
570 (int) Constants.RegionSize, 718 (int)m_scene.RegionInfo.RegionSizeX,
571 (int) Constants.RegionSize); 719 (int)m_scene.RegionInfo.RegionSizeY);
572 m_scene.Heightmap = channel; 720 m_scene.Heightmap = channel;
573 m_channel = channel; 721 m_channel = channel;
574 UpdateRevertMap(); 722 UpdateRevertMap();
@@ -607,23 +755,23 @@ namespace OpenSim.Region.CoreModules.World.Terrain
607 } 755 }
608 756
609 // this region is included in the tile request 757 // this region is included in the tile request
610 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 758 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
611 { 759 {
612 if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) 760 if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave())
613 { 761 {
614 lock (m_scene) 762 lock(m_scene)
615 { 763 {
616 loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, 764 loader.Value.SaveFile(m_channel, filename, offsetX, offsetY,
617 fileWidth, fileHeight, 765 fileWidth, fileHeight,
618 (int)Constants.RegionSize, 766 (int)m_scene.RegionInfo.RegionSizeX,
619 (int)Constants.RegionSize); 767 (int)m_scene.RegionInfo.RegionSizeY);
620 768
621 MainConsole.Instance.OutputFormat( 769 MainConsole.Instance.OutputFormat(
622 "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", 770 "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}",
623 fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, 771 fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1,
624 m_scene.RegionInfo.RegionName, filename); 772 m_scene.RegionInfo.RegionName, filename);
625 } 773 }
626 774
627 return; 775 return;
628 } 776 }
629 } 777 }
@@ -634,7 +782,44 @@ namespace OpenSim.Region.CoreModules.World.Terrain
634 } 782 }
635 783
636 /// <summary> 784 /// <summary>
785 /// Called before processing of every simulation frame.
786 /// This is used to check to see of any of the terrain is tainted and, if so, schedule
787 /// updates for all the presences.
788 /// This also checks to see if there are updates that need to be sent for each presence.
789 /// This is where the logic is to send terrain updates to clients.
790 /// </summary>
791 private void EventManager_OnFrame()
792 {
793 TerrainData terrData = m_channel.GetTerrainData();
794
795 bool shouldTaint = false;
796 for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
797 {
798 for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
799 {
800 if (terrData.IsTaintedAt(x, y))
801 {
802 // Found a patch that was modified. Push this flag into the clients.
803 SendToClients(terrData, x, y);
804 shouldTaint = true;
805 }
806 }
807 }
808
809 // This event also causes changes to be sent to the clients
810 CheckSendingPatchesToClients();
811
812 // If things changes, generate some events
813 if (shouldTaint)
814 {
815 m_scene.EventManager.TriggerTerrainTainted();
816 m_tainted = true;
817 }
818 }
819
820 /// <summary>
637 /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections 821 /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections
822 /// Called infrequently (like every 5 seconds or so). Best used for storing terrain.
638 /// </summary> 823 /// </summary>
639 private void EventManager_OnTerrainTick() 824 private void EventManager_OnTerrainTick()
640 { 825 {
@@ -665,7 +850,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
665 850
666 string[] tmpArgs = new string[args.Length - 2]; 851 string[] tmpArgs = new string[args.Length - 2];
667 int i; 852 int i;
668 for (i = 2; i < args.Length; i++) 853 for(i = 2; i < args.Length; i++)
669 tmpArgs[i - 2] = args[i]; 854 tmpArgs[i - 2] = args[i];
670 855
671 m_commander.ProcessConsoleCommand(args[1], tmpArgs); 856 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
@@ -683,56 +868,50 @@ namespace OpenSim.Region.CoreModules.World.Terrain
683 client.OnLandUndo += client_OnLandUndo; 868 client.OnLandUndo += client_OnLandUndo;
684 client.OnUnackedTerrain += client_OnUnackedTerrain; 869 client.OnUnackedTerrain += client_OnUnackedTerrain;
685 } 870 }
686 871
687 /// <summary> 872 /// <summary>
688 /// Checks to see if the terrain has been modified since last check 873 /// Installs terrain brush hook to IClientAPI
689 /// but won't attempt to limit those changes to the limits specified in the estate settings
690 /// currently invoked by the command line operations in the region server only
691 /// </summary> 874 /// </summary>
692 private void CheckForTerrainUpdates() 875 /// <param name="client"></param>
876 private void EventManager_OnClientClosed(UUID client, Scene scene)
693 { 877 {
694 CheckForTerrainUpdates(false); 878 ScenePresence presence = scene.GetScenePresence(client);
879 if (presence != null)
880 {
881 presence.ControllingClient.OnModifyTerrain -= client_OnModifyTerrain;
882 presence.ControllingClient.OnBakeTerrain -= client_OnBakeTerrain;
883 presence.ControllingClient.OnLandUndo -= client_OnLandUndo;
884 presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
885 }
886
887 lock(m_perClientPatchUpdates)
888 m_perClientPatchUpdates.Remove(client);
695 } 889 }
696 890
697 /// <summary> 891 /// <summary>
698 /// Checks to see if the terrain has been modified since last check. 892 /// Scan over changes in the terrain and limit height changes. This enforces the
699 /// If it has been modified, every all the terrain patches are sent to the client. 893 /// non-estate owner limits on rate of terrain editting.
700 /// If the call is asked to respect the estate settings for terrain_raise_limit and 894 /// Returns 'true' if any heights were limited.
701 /// terrain_lower_limit, it will clamp terrain updates between these values
702 /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces
703 /// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param>
704 /// </summary> 895 /// </summary>
705 private void CheckForTerrainUpdates(bool respectEstateSettings) 896 private bool EnforceEstateLimits()
706 { 897 {
707 bool shouldTaint = false; 898 TerrainData terrData = m_channel.GetTerrainData();
708 float[] serialised = m_channel.GetFloatsSerialised(); 899
709 int x; 900 bool wasLimited = false;
710 for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) 901 for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
711 { 902 {
712 int y; 903 for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
713 for (y = 0; y < m_channel.Height; y += Constants.TerrainPatchSize)
714 { 904 {
715 if (m_channel.Tainted(x, y)) 905 if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
716 { 906 {
717 // if we should respect the estate settings then 907 // If we should respect the estate settings then
718 // fixup and height deltas that don't respect them 908 // fixup and height deltas that don't respect them.
719 if (respectEstateSettings && LimitChannelChanges(x, y)) 909 // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
720 { 910 wasLimited |= LimitChannelChanges(terrData, x, y);
721 // this has been vetoed, so update
722 // what we are going to send to the client
723 serialised = m_channel.GetFloatsSerialised();
724 }
725
726 SendToClients(serialised, x, y);
727 shouldTaint = true;
728 } 911 }
729 } 912 }
730 } 913 }
731 if (shouldTaint) 914 return wasLimited;
732 {
733 m_scene.EventManager.TriggerTerrainTainted();
734 m_tainted = true;
735 }
736 } 915 }
737 916
738 /// <summary> 917 /// <summary>
@@ -740,31 +919,30 @@ namespace OpenSim.Region.CoreModules.World.Terrain
740 /// are all within the current estate limits 919 /// are all within the current estate limits
741 /// <returns>true if changes were limited, false otherwise</returns> 920 /// <returns>true if changes were limited, false otherwise</returns>
742 /// </summary> 921 /// </summary>
743 private bool LimitChannelChanges(int xStart, int yStart) 922 private bool LimitChannelChanges(TerrainData terrData, int xStart, int yStart)
744 { 923 {
745 bool changesLimited = false; 924 bool changesLimited = false;
746 double minDelta = m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; 925 float minDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit;
747 double maxDelta = m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; 926 float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit;
748 927
749 // loop through the height map for this patch and compare it against 928 // loop through the height map for this patch and compare it against
750 // the revert map 929 // the revert map
751 for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) 930 for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++)
752 { 931 {
753 for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) 932 for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
754 { 933 {
755 934 float requestedHeight = terrData[x, y];
756 double requestedHeight = m_channel[x, y]; 935 float bakedHeight = (float)m_revert[x, y];
757 double bakedHeight = m_revert[x, y]; 936 float requestedDelta = requestedHeight - bakedHeight;
758 double requestedDelta = requestedHeight - bakedHeight;
759 937
760 if (requestedDelta > maxDelta) 938 if (requestedDelta > maxDelta)
761 { 939 {
762 m_channel[x, y] = bakedHeight + maxDelta; 940 terrData[x, y] = bakedHeight + maxDelta;
763 changesLimited = true; 941 changesLimited = true;
764 } 942 }
765 else if (requestedDelta < minDelta) 943 else if (requestedDelta < minDelta)
766 { 944 {
767 m_channel[x, y] = bakedHeight + minDelta; //as lower is a -ve delta 945 terrData[x, y] = bakedHeight + minDelta; //as lower is a -ve delta
768 changesLimited = true; 946 changesLimited = true;
769 } 947 }
770 } 948 }
@@ -775,7 +953,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
775 953
776 private void client_OnLandUndo(IClientAPI client) 954 private void client_OnLandUndo(IClientAPI client)
777 { 955 {
778 lock (m_undo) 956 lock(m_undo)
779 { 957 {
780 if (m_undo.Count > 0) 958 if (m_undo.Count > 0)
781 { 959 {
@@ -792,14 +970,177 @@ namespace OpenSim.Region.CoreModules.World.Terrain
792 /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> 970 /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param>
793 /// <param name="x">The patch corner to send</param> 971 /// <param name="x">The patch corner to send</param>
794 /// <param name="y">The patch corner to send</param> 972 /// <param name="y">The patch corner to send</param>
795 private void SendToClients(float[] serialised, int x, int y) 973 private void SendToClients(TerrainData terrData, int x, int y)
796 { 974 {
797 m_scene.ForEachClient( 975 if (m_sendTerrainUpdatesByViewDistance)
798 delegate(IClientAPI controller) 976 {
799 { controller.SendLayerData( 977 // Add that this patch needs to be sent to the accounting for each client.
800 x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); 978 lock(m_perClientPatchUpdates)
979 {
980 m_scene.ForEachScenePresence(presence =>
981 {
982 PatchUpdates thisClientUpdates;
983 if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
984 {
985 // There is a ScenePresence without a send patch map. Create one.
986 thisClientUpdates = new PatchUpdates(terrData, presence);
987 m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
988 }
989 thisClientUpdates.SetByXY(x, y, true);
801 } 990 }
802 ); 991 );
992 }
993 }
994 else
995 {
996 // Legacy update sending where the update is sent out as soon as noticed
997 // We know the actual terrain data that is passed is ignored so this passes a dummy heightmap.
998 //float[] heightMap = terrData.GetFloatsSerialized();
999 float[] heightMap = new float[10];
1000 m_scene.ForEachClient(
1001 delegate(IClientAPI controller)
1002 {
1003 controller.SendLayerData(x / Constants.TerrainPatchSize,
1004 y / Constants.TerrainPatchSize,
1005 heightMap);
1006 }
1007 );
1008 }
1009 }
1010
1011 private class PatchesToSend : IComparable<PatchesToSend>
1012 {
1013 public int PatchX;
1014 public int PatchY;
1015 public float Dist;
1016
1017 public PatchesToSend(int pX, int pY, float pDist)
1018 {
1019 PatchX = pX;
1020 PatchY = pY;
1021 Dist = pDist;
1022 }
1023
1024 public int CompareTo(PatchesToSend other)
1025 {
1026 return Dist.CompareTo(other.Dist);
1027 }
1028 }
1029
1030 // Called each frame time to see if there are any patches to send to any of the
1031 // ScenePresences.
1032 // We know this is only called if we are doing view distance patch sending so some
1033 // tests are not made.
1034 // Loop through all the per-client info and send any patches necessary.
1035 private void CheckSendingPatchesToClients()
1036 {
1037 lock(m_perClientPatchUpdates)
1038 {
1039 foreach(PatchUpdates pups in m_perClientPatchUpdates.Values)
1040 {
1041 if (pups.HasUpdates())
1042 {
1043 // There is something that could be sent to this client.
1044 List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
1045 if (toSend.Count > 0)
1046 {
1047 // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
1048 // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
1049 // Sort the patches to send by the distance from the presence
1050 toSend.Sort();
1051 /* old way that sent individual patches
1052 foreach (PatchesToSend pts in toSend)
1053 {
1054 pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null);
1055 // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land);
1056 }
1057 */
1058
1059 // new way that sends all patches to the protocol so they can be sent in one block
1060 int[] xPieces = new int[toSend.Count];
1061 int[] yPieces = new int[toSend.Count];
1062 float[] patchPieces = new float[toSend.Count * 2];
1063 int pieceIndex = 0;
1064 foreach(PatchesToSend pts in toSend)
1065 {
1066 patchPieces[pieceIndex++] = pts.PatchX;
1067 patchPieces[pieceIndex++] = pts.PatchY;
1068 }
1069 pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces);
1070 }
1071 }
1072 }
1073 }
1074 }
1075
1076 // Compute a list of modified patches that are within our view distance.
1077 private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups)
1078 {
1079 List<PatchesToSend> ret = new List<PatchesToSend>();
1080
1081 ScenePresence presence = pups.Presence;
1082 if (presence == null)
1083 return ret;
1084
1085 Vector3 presencePos = presence.AbsolutePosition;
1086
1087 // Before this distance check, the whole region just showed up. Adding the distance
1088 // check causes different things to happen for the current and adjacent regions.
1089 // So, to keep legacy views, if the region is legacy sized, don't do distance check.
1090 bool isLegacySizedRegion = pups.Terrain.SizeX == Constants.RegionSize && pups.Terrain.SizeY == Constants.RegionSize;
1091 bool shouldCheckViewDistance = m_sendTerrainUpdatesByViewDistance && !isLegacySizedRegion;
1092
1093 int startX = 0;
1094 int endX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize;
1095 int startY = 0;
1096 int endY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize;
1097
1098 // The following only reduces the size of area scanned for updates. Only significant for very large varregions.
1099 if (shouldCheckViewDistance)
1100 {
1101 // Compute the area of patches within our draw distance
1102 startX = (((int)(presencePos.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2;
1103 startX = Math.Max(startX, 0);
1104 startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
1105 startY = (((int)(presencePos.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2;
1106 startY = Math.Max(startY, 0);
1107 startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize);
1108 endX = (((int)(presencePos.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
1109 endX = Math.Max(endX, 0);
1110 endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
1111 endY = (((int)(presencePos.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
1112 endY = Math.Max(endY, 0);
1113 endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize);
1114 }
1115
1116 // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, cpos={4}, isChild={5}, start=<{6},{7}>, end=<{8},{9}>",
1117 // LogHeader, m_scene.RegionInfo.RegionName,
1118 // presence.DrawDistance, presencePos, presence.CameraPosition,
1119 // isLegacySizeChildRegion,
1120 // startX, startY, endX, endY);
1121 for(int x = startX; x < endX; x++)
1122 {
1123 for(int y = startY; y < endY; y++)
1124 {
1125 //Need to make sure we don't send the same ones over and over
1126 Vector3 patchPos = new Vector3(x * Constants.TerrainPatchSize, y * Constants.TerrainPatchSize, presencePos.Z);
1127 if (pups.GetByPatch(x, y))
1128 {
1129 //Check which has less distance, camera or avatar position, both have to be done.
1130 //Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off
1131 if (!shouldCheckViewDistance
1132 || Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50)
1133 || Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50))
1134 {
1135 //They can see it, send it to them
1136 pups.SetByPatch(x, y, false);
1137 float dist = Vector3.DistanceSquared(presencePos, patchPos);
1138 ret.Add(new PatchesToSend(x, y, dist));
1139 }
1140 }
1141 }
1142 }
1143 return ret;
803 } 1144 }
804 1145
805 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action, 1146 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action,
@@ -809,28 +1150,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
809 bool allowed = false; 1150 bool allowed = false;
810 if (north == south && east == west) 1151 if (north == south && east == west)
811 { 1152 {
812 if (m_painteffects.ContainsKey((StandardTerrainEffects) action)) 1153 if (m_painteffects.ContainsKey((StandardTerrainEffects)action))
813 { 1154 {
814 bool[,] allowMask = new bool[m_channel.Width,m_channel.Height]; 1155 bool[,] allowMask = new bool[m_channel.Width, m_channel.Height];
815 allowMask.Initialize(); 1156 allowMask.Initialize();
816 int n = size + 1; 1157 int n = size + 1;
817 if (n > 2) 1158 if (n > 2)
818 n = 4; 1159 n = 4;
819 1160
820 int zx = (int) (west + 0.5); 1161 int zx = (int)(west + 0.5);
821 int zy = (int) (north + 0.5); 1162 int zy = (int)(north + 0.5);
822 1163
823 int dx; 1164 int dx;
824 for (dx=-n; dx<=n; dx++) 1165 for(dx=-n; dx<=n; dx++)
825 { 1166 {
826 int dy; 1167 int dy;
827 for (dy=-n; dy<=n; dy++) 1168 for(dy=-n; dy<=n; dy++)
828 { 1169 {
829 int x = zx + dx; 1170 int x = zx + dx;
830 int y = zy + dy; 1171 int y = zy + dy;
831 if (x>=0 && y>=0 && x<m_channel.Width && y<m_channel.Height) 1172 if (x >= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height)
832 { 1173 {
833 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) 1174 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
834 { 1175 {
835 allowMask[x, y] = true; 1176 allowMask[x, y] = true;
836 allowed = true; 1177 allowed = true;
@@ -841,10 +1182,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
841 if (allowed) 1182 if (allowed)
842 { 1183 {
843 StoreUndoState(); 1184 StoreUndoState();
844 m_painteffects[(StandardTerrainEffects) action].PaintEffect( 1185 m_painteffects[(StandardTerrainEffects)action].PaintEffect(
845 m_channel, allowMask, west, south, height, size, seconds); 1186 m_channel, allowMask, west, south, height, size, seconds);
846 1187
847 CheckForTerrainUpdates(!god); //revert changes outside estate limits 1188 //revert changes outside estate limits
1189 if (!god)
1190 EnforceEstateLimits();
848 } 1191 }
849 } 1192 }
850 else 1193 else
@@ -854,22 +1197,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
854 } 1197 }
855 else 1198 else
856 { 1199 {
857 if (m_floodeffects.ContainsKey((StandardTerrainEffects) action)) 1200 if (m_floodeffects.ContainsKey((StandardTerrainEffects)action))
858 { 1201 {
859 bool[,] fillArea = new bool[m_channel.Width,m_channel.Height]; 1202 bool[,] fillArea = new bool[m_channel.Width, m_channel.Height];
860 fillArea.Initialize(); 1203 fillArea.Initialize();
861 1204
862 int x; 1205 int x;
863 for (x = 0; x < m_channel.Width; x++) 1206 for(x = 0; x < m_channel.Width; x++)
864 { 1207 {
865 int y; 1208 int y;
866 for (y = 0; y < m_channel.Height; y++) 1209 for(y = 0; y < m_channel.Height; y++)
867 { 1210 {
868 if (x < east && x > west) 1211 if (x < east && x > west)
869 { 1212 {
870 if (y < north && y > south) 1213 if (y < north && y > south)
871 { 1214 {
872 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) 1215 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
873 { 1216 {
874 fillArea[x, y] = true; 1217 fillArea[x, y] = true;
875 allowed = true; 1218 allowed = true;
@@ -882,10 +1225,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
882 if (allowed) 1225 if (allowed)
883 { 1226 {
884 StoreUndoState(); 1227 StoreUndoState();
885 m_floodeffects[(StandardTerrainEffects) action].FloodEffect( 1228 m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size);
886 m_channel, fillArea, size);
887 1229
888 CheckForTerrainUpdates(!god); //revert changes outside estate limits 1230 //revert changes outside estate limits
1231 if (!god)
1232 EnforceEstateLimits();
889 } 1233 }
890 } 1234 }
891 else 1235 else
@@ -905,16 +1249,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
905 InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter 1249 InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter
906 } 1250 }
907 } 1251 }
908 1252
909 protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) 1253 protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY)
910 { 1254 {
911 //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); 1255 //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
912 client.SendLayerData(patchX, patchY, m_scene.Heightmap.GetFloatsSerialised()); 1256 // SendLayerData does not use the heightmap parameter. This kludge is so as to not change IClientAPI.
1257 float[] heightMap = new float[10];
1258 client.SendLayerData(patchX, patchY, heightMap);
913 } 1259 }
914 1260
915 private void StoreUndoState() 1261 private void StoreUndoState()
916 { 1262 {
917 lock (m_undo) 1263 lock(m_undo)
918 { 1264 {
919 if (m_undo.Count > 0) 1265 if (m_undo.Count > 0)
920 { 1266 {
@@ -935,23 +1281,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain
935 1281
936 private void InterfaceLoadFile(Object[] args) 1282 private void InterfaceLoadFile(Object[] args)
937 { 1283 {
938 LoadFromFile((string) args[0]); 1284 LoadFromFile((string)args[0]);
939 CheckForTerrainUpdates();
940 } 1285 }
941 1286
942 private void InterfaceLoadTileFile(Object[] args) 1287 private void InterfaceLoadTileFile(Object[] args)
943 { 1288 {
944 LoadFromFile((string) args[0], 1289 LoadFromFile((string)args[0],
945 (int) args[1], 1290 (int)args[1],
946 (int) args[2], 1291 (int)args[2],
947 (int) args[3], 1292 (int)args[3],
948 (int) args[4]); 1293 (int)args[4]);
949 CheckForTerrainUpdates();
950 } 1294 }
951 1295
952 private void InterfaceSaveFile(Object[] args) 1296 private void InterfaceSaveFile(Object[] args)
953 { 1297 {
954 SaveToFile((string) args[0]); 1298 SaveToFile((string)args[0]);
955 } 1299 }
956 1300
957 private void InterfaceSaveTileFile(Object[] args) 1301 private void InterfaceSaveTileFile(Object[] args)
@@ -971,11 +1315,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
971 private void InterfaceRevertTerrain(Object[] args) 1315 private void InterfaceRevertTerrain(Object[] args)
972 { 1316 {
973 int x, y; 1317 int x, y;
974 for (x = 0; x < m_channel.Width; x++) 1318 for(x = 0; x < m_channel.Width; x++)
975 for (y = 0; y < m_channel.Height; y++) 1319 for(y = 0; y < m_channel.Height; y++)
976 m_channel[x, y] = m_revert[x, y]; 1320 m_channel[x, y] = m_revert[x, y];
977 1321
978 CheckForTerrainUpdates();
979 } 1322 }
980 1323
981 private void InterfaceFlipTerrain(Object[] args) 1324 private void InterfaceFlipTerrain(Object[] args)
@@ -984,39 +1327,36 @@ namespace OpenSim.Region.CoreModules.World.Terrain
984 1327
985 if (direction.ToLower().StartsWith("y")) 1328 if (direction.ToLower().StartsWith("y"))
986 { 1329 {
987 for (int x = 0; x < Constants.RegionSize; x++) 1330 for(int x = 0; x < m_channel.Width; x++)
988 { 1331 {
989 for (int y = 0; y < Constants.RegionSize / 2; y++) 1332 for(int y = 0; y < m_channel.Height / 2; y++)
990 { 1333 {
991 double height = m_channel[x, y]; 1334 double height = m_channel[x, y];
992 double flippedHeight = m_channel[x, (int)Constants.RegionSize - 1 - y]; 1335 double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y];
993 m_channel[x, y] = flippedHeight; 1336 m_channel[x, y] = flippedHeight;
994 m_channel[x, (int)Constants.RegionSize - 1 - y] = height; 1337 m_channel[x, (int)m_channel.Height - 1 - y] = height;
995 1338
996 } 1339 }
997 } 1340 }
998 } 1341 }
999 else if (direction.ToLower().StartsWith("x")) 1342 else if (direction.ToLower().StartsWith("x"))
1000 { 1343 {
1001 for (int y = 0; y < Constants.RegionSize; y++) 1344 for(int y = 0; y < m_channel.Height; y++)
1002 { 1345 {
1003 for (int x = 0; x < Constants.RegionSize / 2; x++) 1346 for(int x = 0; x < m_channel.Width / 2; x++)
1004 { 1347 {
1005 double height = m_channel[x, y]; 1348 double height = m_channel[x, y];
1006 double flippedHeight = m_channel[(int)Constants.RegionSize - 1 - x, y]; 1349 double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y];
1007 m_channel[x, y] = flippedHeight; 1350 m_channel[x, y] = flippedHeight;
1008 m_channel[(int)Constants.RegionSize - 1 - x, y] = height; 1351 m_channel[(int)m_channel.Width - 1 - x, y] = height;
1009 1352
1010 } 1353 }
1011 } 1354 }
1012 } 1355 }
1013 else 1356 else
1014 { 1357 {
1015 m_log.Error("Unrecognised direction - need x or y"); 1358 MainConsole.Instance.OutputFormat("ERROR: Unrecognised direction {0} - need x or y", direction);
1016 } 1359 }
1017
1018
1019 CheckForTerrainUpdates();
1020 } 1360 }
1021 1361
1022 private void InterfaceRescaleTerrain(Object[] args) 1362 private void InterfaceRescaleTerrain(Object[] args)
@@ -1042,9 +1382,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1042 int width = m_channel.Width; 1382 int width = m_channel.Width;
1043 int height = m_channel.Height; 1383 int height = m_channel.Height;
1044 1384
1045 for (int x = 0; x < width; x++) 1385 for(int x = 0; x < width; x++)
1046 { 1386 {
1047 for (int y = 0; y < height; y++) 1387 for(int y = 0; y < height; y++)
1048 { 1388 {
1049 double currHeight = m_channel[x, y]; 1389 double currHeight = m_channel[x, y];
1050 if (currHeight < currMin) 1390 if (currHeight < currMin)
@@ -1065,16 +1405,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1065 //m_log.InfoFormat("Scale = {0}", scale); 1405 //m_log.InfoFormat("Scale = {0}", scale);
1066 1406
1067 // scale the heightmap accordingly 1407 // scale the heightmap accordingly
1068 for (int x = 0; x < width; x++) 1408 for(int x = 0; x < width; x++)
1069 { 1409 {
1070 for (int y = 0; y < height; y++) 1410 for(int y = 0; y < height; y++)
1071 { 1411 {
1072 double currHeight = m_channel[x, y] - currMin; 1412 double currHeight = m_channel[x, y] - currMin;
1073 m_channel[x, y] = desiredMin + (currHeight * scale); 1413 m_channel[x, y] = desiredMin + (currHeight * scale);
1074 } 1414 }
1075 } 1415 }
1076 1416
1077 CheckForTerrainUpdates();
1078 } 1417 }
1079 1418
1080 } 1419 }
@@ -1082,64 +1421,73 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1082 private void InterfaceElevateTerrain(Object[] args) 1421 private void InterfaceElevateTerrain(Object[] args)
1083 { 1422 {
1084 int x, y; 1423 int x, y;
1085 for (x = 0; x < m_channel.Width; x++) 1424 for(x = 0; x < m_channel.Width; x++)
1086 for (y = 0; y < m_channel.Height; y++) 1425 for(y = 0; y < m_channel.Height; y++)
1087 m_channel[x, y] += (double) args[0]; 1426 m_channel[x, y] += (double)args[0];
1088 CheckForTerrainUpdates();
1089 } 1427 }
1090 1428
1091 private void InterfaceMultiplyTerrain(Object[] args) 1429 private void InterfaceMultiplyTerrain(Object[] args)
1092 { 1430 {
1093 int x, y; 1431 int x, y;
1094 for (x = 0; x < m_channel.Width; x++) 1432 for(x = 0; x < m_channel.Width; x++)
1095 for (y = 0; y < m_channel.Height; y++) 1433 for(y = 0; y < m_channel.Height; y++)
1096 m_channel[x, y] *= (double) args[0]; 1434 m_channel[x, y] *= (double)args[0];
1097 CheckForTerrainUpdates();
1098 } 1435 }
1099 1436
1100 private void InterfaceLowerTerrain(Object[] args) 1437 private void InterfaceLowerTerrain(Object[] args)
1101 { 1438 {
1102 int x, y; 1439 int x, y;
1103 for (x = 0; x < m_channel.Width; x++) 1440 for(x = 0; x < m_channel.Width; x++)
1104 for (y = 0; y < m_channel.Height; y++) 1441 for(y = 0; y < m_channel.Height; y++)
1105 m_channel[x, y] -= (double) args[0]; 1442 m_channel[x, y] -= (double)args[0];
1106 CheckForTerrainUpdates();
1107 } 1443 }
1108 1444
1109 private void InterfaceFillTerrain(Object[] args) 1445 public void InterfaceFillTerrain(Object[] args)
1110 { 1446 {
1111 int x, y; 1447 int x, y;
1112 1448
1113 for (x = 0; x < m_channel.Width; x++) 1449 for(x = 0; x < m_channel.Width; x++)
1114 for (y = 0; y < m_channel.Height; y++) 1450 for(y = 0; y < m_channel.Height; y++)
1115 m_channel[x, y] = (double) args[0]; 1451 m_channel[x, y] = (double)args[0];
1116 CheckForTerrainUpdates();
1117 } 1452 }
1118 1453
1119 private void InterfaceMinTerrain(Object[] args) 1454 private void InterfaceMinTerrain(Object[] args)
1120 { 1455 {
1121 int x, y; 1456 int x, y;
1122 for (x = 0; x < m_channel.Width; x++) 1457 for(x = 0; x < m_channel.Width; x++)
1123 { 1458 {
1124 for (y = 0; y < m_channel.Height; y++) 1459 for(y = 0; y < m_channel.Height; y++)
1125 { 1460 {
1126 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); 1461 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]);
1127 } 1462 }
1128 } 1463 }
1129 CheckForTerrainUpdates();
1130 } 1464 }
1131 1465
1132 private void InterfaceMaxTerrain(Object[] args) 1466 private void InterfaceMaxTerrain(Object[] args)
1133 { 1467 {
1134 int x, y; 1468 int x, y;
1135 for (x = 0; x < m_channel.Width; x++) 1469 for(x = 0; x < m_channel.Width; x++)
1136 { 1470 {
1137 for (y = 0; y < m_channel.Height; y++) 1471 for(y = 0; y < m_channel.Height; y++)
1138 { 1472 {
1139 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); 1473 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]);
1140 } 1474 }
1141 } 1475 }
1142 CheckForTerrainUpdates(); 1476 }
1477
1478 private void InterfaceShow(Object[] args)
1479 {
1480 Vector2 point;
1481
1482 if (!ConsoleUtil.TryParseConsole2DVector((string)args[0], null, out point))
1483 {
1484 Console.WriteLine("ERROR: {0} is not a valid vector", args[0]);
1485 return;
1486 }
1487
1488 double height = m_channel[(int)point.X, (int)point.Y];
1489
1490 Console.WriteLine("Terrain height at {0} is {1}", point, height);
1143 } 1491 }
1144 1492
1145 private void InterfaceShowDebugStats(Object[] args) 1493 private void InterfaceShowDebugStats(Object[] args)
@@ -1149,10 +1497,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1149 double sum = 0; 1497 double sum = 0;
1150 1498
1151 int x; 1499 int x;
1152 for (x = 0; x < m_channel.Width; x++) 1500 for(x = 0; x < m_channel.Width; x++)
1153 { 1501 {
1154 int y; 1502 int y;
1155 for (y = 0; y < m_channel.Height; y++) 1503 for(y = 0; y < m_channel.Height; y++)
1156 { 1504 {
1157 sum += m_channel[x, y]; 1505 sum += m_channel[x, y];
1158 if (max < m_channel[x, y]) 1506 if (max < m_channel[x, y])
@@ -1164,13 +1512,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1164 1512
1165 double avg = sum / (m_channel.Height * m_channel.Width); 1513 double avg = sum / (m_channel.Height * m_channel.Width);
1166 1514
1167 m_log.Info("Channel " + m_channel.Width + "x" + m_channel.Height); 1515 MainConsole.Instance.OutputFormat("Channel {0}x{1}", m_channel.Width, m_channel.Height);
1168 m_log.Info("max/min/avg/sum: " + max + "/" + min + "/" + avg + "/" + sum); 1516 MainConsole.Instance.OutputFormat("max/min/avg/sum: {0}/{1}/{2}/{3}", max, min, avg, sum);
1169 } 1517 }
1170 1518
1171 private void InterfaceEnableExperimentalBrushes(Object[] args) 1519 private void InterfaceEnableExperimentalBrushes(Object[] args)
1172 { 1520 {
1173 if ((bool) args[0]) 1521 if ((bool)args[0])
1174 { 1522 {
1175 m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); 1523 m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere();
1176 m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); 1524 m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere();
@@ -1185,28 +1533,30 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1185 private void InterfaceRunPluginEffect(Object[] args) 1533 private void InterfaceRunPluginEffect(Object[] args)
1186 { 1534 {
1187 string firstArg = (string)args[0]; 1535 string firstArg = (string)args[0];
1536
1188 if (firstArg == "list") 1537 if (firstArg == "list")
1189 { 1538 {
1190 m_log.Info("List of loaded plugins"); 1539 MainConsole.Instance.Output("List of loaded plugins");
1191 foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects) 1540 foreach(KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects)
1192 { 1541 {
1193 m_log.Info(kvp.Key); 1542 MainConsole.Instance.Output(kvp.Key);
1194 } 1543 }
1195 return; 1544 return;
1196 } 1545 }
1546
1197 if (firstArg == "reload") 1547 if (firstArg == "reload")
1198 { 1548 {
1199 LoadPlugins(); 1549 LoadPlugins();
1200 return; 1550 return;
1201 } 1551 }
1552
1202 if (m_plugineffects.ContainsKey(firstArg)) 1553 if (m_plugineffects.ContainsKey(firstArg))
1203 { 1554 {
1204 m_plugineffects[firstArg].RunEffect(m_channel); 1555 m_plugineffects[firstArg].RunEffect(m_channel);
1205 CheckForTerrainUpdates();
1206 } 1556 }
1207 else 1557 else
1208 { 1558 {
1209 m_log.Warn("No such plugin effect loaded."); 1559 MainConsole.Instance.Output("WARNING: No such plugin effect {0} loaded.", firstArg);
1210 } 1560 }
1211 } 1561 }
1212 1562
@@ -1295,12 +1645,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1295 new Command("stats", CommandIntentions.COMMAND_STATISTICAL, InterfaceShowDebugStats, 1645 new Command("stats", CommandIntentions.COMMAND_STATISTICAL, InterfaceShowDebugStats,
1296 "Shows some information about the regions heightmap for debugging purposes."); 1646 "Shows some information about the regions heightmap for debugging purposes.");
1297 1647
1648 Command showCommand =
1649 new Command("show", CommandIntentions.COMMAND_NON_HAZARDOUS, InterfaceShow,
1650 "Shows terrain height at a given co-ordinate.");
1651 showCommand.AddArgument("point", "point in <x>,<y> format with no spaces (e.g. 45,45)", "String");
1652
1298 Command experimentalBrushesCommand = 1653 Command experimentalBrushesCommand =
1299 new Command("newbrushes", CommandIntentions.COMMAND_HAZARDOUS, InterfaceEnableExperimentalBrushes, 1654 new Command("newbrushes", CommandIntentions.COMMAND_HAZARDOUS, InterfaceEnableExperimentalBrushes,
1300 "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time."); 1655 "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time.");
1301 experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean"); 1656 experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean");
1302 1657
1303 //Plugins 1658 // Plugins
1304 Command pluginRunCommand = 1659 Command pluginRunCommand =
1305 new Command("effect", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRunPluginEffect, "Runs a specified plugin effect"); 1660 new Command("effect", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRunPluginEffect, "Runs a specified plugin effect");
1306 pluginRunCommand.AddArgument("name", "The plugin effect you wish to run, or 'list' to see all plugins", "String"); 1661 pluginRunCommand.AddArgument("name", "The plugin effect you wish to run, or 'list' to see all plugins", "String");
@@ -1316,6 +1671,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1316 m_commander.RegisterCommand("bake", bakeRegionCommand); 1671 m_commander.RegisterCommand("bake", bakeRegionCommand);
1317 m_commander.RegisterCommand("revert", revertRegionCommand); 1672 m_commander.RegisterCommand("revert", revertRegionCommand);
1318 m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand); 1673 m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand);
1674 m_commander.RegisterCommand("show", showCommand);
1319 m_commander.RegisterCommand("stats", showDebugStatsCommand); 1675 m_commander.RegisterCommand("stats", showDebugStatsCommand);
1320 m_commander.RegisterCommand("effect", pluginRunCommand); 1676 m_commander.RegisterCommand("effect", pluginRunCommand);
1321 m_commander.RegisterCommand("flip", flipCommand); 1677 m_commander.RegisterCommand("flip", flipCommand);
@@ -1325,10 +1681,66 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1325 1681
1326 // Add this to our scene so scripts can call these functions 1682 // Add this to our scene so scripts can call these functions
1327 m_scene.RegisterModuleCommander(m_commander); 1683 m_scene.RegisterModuleCommander(m_commander);
1684
1685 // Add Modify command to Scene, since Command object requires fixed-length arglists
1686 m_scene.AddCommand("Terrain", this, "terrain modify",
1687 "terrain modify <operation> <value> [<area>] [<taper>]",
1688 "Modifies the terrain as instructed." +
1689 "\nEach operation can be limited to an area of effect:" +
1690 "\n * -ell=x,y,rx[,ry] constrains the operation to an ellipse centred at x,y" +
1691 "\n * -rec=x,y,dx[,dy] constrains the operation to a rectangle based at x,y" +
1692 "\nEach operation can have its effect tapered based on distance from centre:" +
1693 "\n * elliptical operations taper as cones" +
1694 "\n * rectangular operations taper as pyramids"
1695 ,
1696 ModifyCommand);
1697
1328 } 1698 }
1329 1699
1700 public void ModifyCommand(string module, string[] cmd)
1701 {
1702 string result;
1703 Scene scene = SceneManager.Instance.CurrentScene;
1704 if ((scene != null) && (scene != m_scene))
1705 {
1706 result = String.Empty;
1707 }
1708 else if (cmd.Length > 2)
1709 {
1710 string operationType = cmd[2];
1330 1711
1331 #endregion 1712
1713 ITerrainModifier operation;
1714 if (!m_modifyOperations.TryGetValue(operationType, out operation))
1715 {
1716 result = String.Format("Terrain Modify \"{0}\" not found.", operationType);
1717 }
1718 else if ((cmd.Length > 3) && (cmd[3] == "usage"))
1719 {
1720 result = "Usage: " + operation.GetUsage();
1721 }
1722 else
1723 {
1724 result = operation.ModifyTerrain(m_channel, cmd);
1725 }
1726
1727 if (result == String.Empty)
1728 {
1729 result = "Modified terrain";
1730 m_log.DebugFormat("Performed terrain operation {0}", operationType);
1731 }
1732 }
1733 else
1734 {
1735 result = "Usage: <operation-name> <arg1> <arg2>...";
1736 }
1737 if (result != String.Empty)
1738 {
1739 MainConsole.Instance.Output(result);
1740 }
1741 }
1742
1743#endregion
1332 1744
1333 } 1745 }
1334} 1746}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs
new file mode 100644
index 0000000..0563ad0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs
@@ -0,0 +1,75 @@
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
28using System;
29using NUnit.Framework;
30using OpenSim.Framework;
31using OpenSim.Region.CoreModules.World.Terrain;
32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Tests.Common;
34
35namespace OpenSim.Region.CoreModules.Terrain.Tests
36{
37 public class TerrainModuleTests : OpenSimTestCase
38 {
39 [Test]
40 public void TestTerrainFill()
41 {
42 TestHelpers.InMethod();
43// TestHelpers.EnableLogging();
44
45 //UUID userId = TestHelpers.ParseTail(0x1);
46
47 TerrainModule tm = new TerrainModule();
48 Scene scene = new SceneHelpers().SetupScene();
49 SceneHelpers.SetupSceneModules(scene, tm);
50
51 // Fillheight of 30
52 {
53 double fillHeight = 30;
54
55 tm.InterfaceFillTerrain(new object[] { fillHeight });
56
57 double height = scene.Heightmap[128, 128];
58
59 Assert.AreEqual(fillHeight, height);
60 }
61
62 // Max fillheight of 30
63 // According to http://wiki.secondlife.com/wiki/Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files#Notes_for_Creating_Height_Field_Maps_for_Second_Life
64 {
65 double fillHeight = 508;
66
67 tm.InterfaceFillTerrain(new object[] { fillHeight });
68
69 double height = scene.Heightmap[128, 128];
70
71 Assert.AreEqual(fillHeight, height);
72 }
73 }
74 }
75} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
index be719ea..29e80ef 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
@@ -40,10 +40,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
40 [Test] 40 [Test]
41 public void BrushTest() 41 public void BrushTest()
42 { 42 {
43 int midRegion = (int)Constants.RegionSize / 2;
44
45 // Create a mask that covers only the left half of the region
43 bool[,] allowMask = new bool[(int)Constants.RegionSize, 256]; 46 bool[,] allowMask = new bool[(int)Constants.RegionSize, 256];
44 int x; 47 int x;
45 int y; 48 int y;
46 for (x = 0; x < (int)((int)Constants.RegionSize * 0.5f); x++) 49 for (x = 0; x < midRegion; x++)
47 { 50 {
48 for (y = 0; y < (int)Constants.RegionSize; y++) 51 for (y = 0; y < (int)Constants.RegionSize; y++)
49 { 52 {
@@ -57,13 +60,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
57 TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); 60 TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize);
58 ITerrainPaintableEffect effect = new RaiseSphere(); 61 ITerrainPaintableEffect effect = new RaiseSphere();
59 62
60 effect.PaintEffect(map, allowMask, (int)Constants.RegionSize * 0.5f, (int)Constants.RegionSize * 0.5f, -1.0, 2, 0.1); 63 effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
61 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (127,128)."); 64 Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128).");
62 Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (124,128)."); 65 Assert.That(map[125, midRegion] > 0.0, "Raise brush should raising value at this point (124,128).");
63 Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (123,128)."); 66 Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128).");
64 Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (128,128)."); 67 Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128).");
65 Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (0,128)."); 68 Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128).");
66
67 // 69 //
68 // Test LowerSphere 70 // Test LowerSphere
69 // 71 //
@@ -77,13 +79,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
77 } 79 }
78 effect = new LowerSphere(); 80 effect = new LowerSphere();
79 81
80 effect.PaintEffect(map, allowMask, ((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), -1.0, 2, 6.0); 82 effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
81 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); 83 Assert.That(map[127, midRegion] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128).");
82 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); 84 Assert.That(map[127, midRegion] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128).");
83 Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] < 1.0, "Lower brush should lowering value at this point (124,128)."); 85 Assert.That(map[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128).");
84 Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (123,128)."); 86 Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128).");
85 Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (128,128)."); 87 Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128).");
86 Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (0,128)."); 88 Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128).");
87 } 89 }
88 90
89 [Test] 91 [Test]
@@ -100,10 +102,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
100 x[0, 0] -= 1.0; 102 x[0, 0] -= 1.0;
101 Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error."); 103 Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error.");
102 104
103 x[0, 0] = Math.PI;
104 double[,] doublesExport = x.GetDoubles();
105 Assert.That(doublesExport[0, 0] == Math.PI, "Export to double[,] array not working correctly.");
106
107 x[0, 0] = 1.0; 105 x[0, 0] = 1.0;
108 float[] floatsExport = x.GetFloatsSerialised(); 106 float[] floatsExport = x.GetFloatsSerialised();
109 Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly."); 107 Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly.");
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs
index df5ac92..9534ad3 100644
--- a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs
+++ b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -32,6 +32,7 @@ using System.Drawing.Imaging;
32using log4net; 32using log4net;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Services.Interfaces; 36using OpenSim.Services.Interfaces;
36 37
37namespace OpenSim.Region.CoreModules.World.Warp3DMap 38namespace OpenSim.Region.CoreModules.World.Warp3DMap
@@ -66,261 +67,271 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
66 #endregion Constants 67 #endregion Constants
67 68
68 private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); 69 private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
70 private static string LogHeader = "[WARP3D TERRAIN SPLAT]";
69 71
70 /// <summary> 72 /// <summary>
71 /// Builds a composited terrain texture given the region texture 73 /// Builds a composited terrain texture given the region texture
72 /// and heightmap settings 74 /// and heightmap settings
73 /// </summary> 75 /// </summary>
74 /// <param name="heightmap">Terrain heightmap</param> 76 /// <param name="terrain">Terrain heightmap</param>
75 /// <param name="regionInfo">Region information including terrain texture parameters</param> 77 /// <param name="regionInfo">Region information including terrain texture parameters</param>
76 /// <returns>A composited 256x256 RGB texture ready for rendering</returns> 78 /// <returns>A 256x256 square RGB texture ready for rendering</returns>
77 /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting 79 /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting
80 /// Note we create a 256x256 dimension texture even if the actual terrain is larger.
78 /// </remarks> 81 /// </remarks>
79 public static Bitmap Splat(float[] heightmap, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetService assetService, bool textureTerrain) 82 public static Bitmap Splat(ITerrainChannel terrain,
83 UUID[] textureIDs, float[] startHeights, float[] heightRanges,
84 Vector3d regionPosition, IAssetService assetService, bool textureTerrain)
80 { 85 {
81 Debug.Assert(heightmap.Length == 256 * 256);
82 Debug.Assert(textureIDs.Length == 4); 86 Debug.Assert(textureIDs.Length == 4);
83 Debug.Assert(startHeights.Length == 4); 87 Debug.Assert(startHeights.Length == 4);
84 Debug.Assert(heightRanges.Length == 4); 88 Debug.Assert(heightRanges.Length == 4);
85 89
86 Bitmap[] detailTexture = new Bitmap[4]; 90 Bitmap[] detailTexture = new Bitmap[4];
87 Bitmap output = null;
88 BitmapData outputData = null;
89 91
90 try 92 if (textureTerrain)
91 { 93 {
92 if (textureTerrain) 94 // Swap empty terrain textureIDs with default IDs
95 for (int i = 0; i < textureIDs.Length; i++)
93 { 96 {
94 // Swap empty terrain textureIDs with default IDs 97 if (textureIDs[i] == UUID.Zero)
95 for (int i = 0; i < textureIDs.Length; i++) 98 textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
96 { 99 }
97 if (textureIDs[i] == UUID.Zero) 100
98 textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; 101 #region Texture Fetching
99 } 102
100 103 if (assetService != null)
101 #region Texture Fetching 104 {
102 105 for (int i = 0; i < 4; i++)
103 if (assetService != null)
104 { 106 {
105 for (int i = 0; i < 4; i++) 107 AssetBase asset;
108 UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]);
109
110 // Try to fetch a cached copy of the decoded/resized version of this texture
111 asset = assetService.GetCached(cacheID.ToString());
112 if (asset != null)
113 {
114 try
115 {
116 using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
117 detailTexture[i] = (Bitmap)Image.FromStream(stream);
118 }
119 catch (Exception ex)
120 {
121 m_log.Warn("Failed to decode cached terrain texture " + cacheID +
122 " (textureID: " + textureIDs[i] + "): " + ex.Message);
123 }
124 }
125
126 if (detailTexture[i] == null)
106 { 127 {
107 AssetBase asset; 128 // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
108 UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); 129 asset = assetService.Get(textureIDs[i].ToString());
109
110 // Try to fetch a cached copy of the decoded/resized version of this texture
111 asset = assetService.GetCached(cacheID.ToString());
112 if (asset != null) 130 if (asset != null)
113 { 131 {
114// m_log.DebugFormat( 132// m_log.DebugFormat(
115// "[TERRAIN SPLAT]: Got asset service cached terrain texture {0} {1}", i, asset.ID); 133// "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID);
116 134
117 try 135 try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
118 {
119 using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
120 detailTexture[i] = (Bitmap)Image.FromStream(stream);
121 }
122 catch (Exception ex) 136 catch (Exception ex)
123 { 137 {
124 m_log.Warn("Failed to decode cached terrain texture " + cacheID + 138 m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
125 " (textureID: " + textureIDs[i] + "): " + ex.Message);
126 } 139 }
127 } 140 }
128
129 if (detailTexture[i] == null)
130 {
131 // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
132 asset = assetService.Get(textureIDs[i].ToString());
133 if (asset != null)
134 {
135// m_log.DebugFormat(
136// "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID);
137 141
138 try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } 142 if (detailTexture[i] != null)
139 catch (Exception ex) 143 {
144 // Make sure this texture is the correct size, otherwise resize
145 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
146 {
147 using (Bitmap origBitmap = detailTexture[i])
140 { 148 {
141 m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); 149 detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256);
142 } 150 }
143 } 151 }
144 152
145 if (detailTexture[i] != null) 153 // Save the decoded and resized texture to the cache
146 { 154 byte[] data;
147 // Make sure this texture is the correct size, otherwise resize 155 using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
148 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) 156 {
149 { 157 detailTexture[i].Save(stream, ImageFormat.Png);
150 using (Bitmap origBitmap = detailTexture[i]) 158 data = stream.ToArray();
151 {
152 detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256);
153 }
154 }
155
156 // Save the decoded and resized texture to the cache
157 byte[] data;
158 using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
159 {
160 detailTexture[i].Save(stream, ImageFormat.Png);
161 data = stream.ToArray();
162 }
163
164 // Cache a PNG copy of this terrain texture
165 AssetBase newAsset = new AssetBase
166 {
167 Data = data,
168 Description = "PNG",
169 Flags = AssetFlags.Collectable,
170 FullID = cacheID,
171 ID = cacheID.ToString(),
172 Local = true,
173 Name = String.Empty,
174 Temporary = true,
175 Type = (sbyte)AssetType.Unknown
176 };
177 newAsset.Metadata.ContentType = "image/png";
178 assetService.Store(newAsset);
179 } 159 }
160
161 // Cache a PNG copy of this terrain texture
162 AssetBase newAsset = new AssetBase
163 {
164 Data = data,
165 Description = "PNG",
166 Flags = AssetFlags.Collectable,
167 FullID = cacheID,
168 ID = cacheID.ToString(),
169 Local = true,
170 Name = String.Empty,
171 Temporary = true,
172 Type = (sbyte)AssetType.Unknown
173 };
174 newAsset.Metadata.ContentType = "image/png";
175 assetService.Store(newAsset);
180 } 176 }
181 } 177 }
182 } 178 }
183
184 #endregion Texture Fetching
185 } 179 }
186 180
187 // Fill in any missing textures with a solid color 181 #endregion Texture Fetching
188 for (int i = 0; i < 4; i++) 182 }
183
184 // Fill in any missing textures with a solid color
185 for (int i = 0; i < 4; i++)
186 {
187 if (detailTexture[i] == null)
189 { 188 {
190 if (detailTexture[i] == null) 189 m_log.DebugFormat("{0} Missing terrain texture for layer {1}. Filling with solid default color",
190 LogHeader, i);
191 // Create a solid color texture for this layer
192 detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
193 using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
191 { 194 {
192// m_log.DebugFormat( 195 using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
193// "[TERRAIN SPLAT]: Generating solid colour for missing texture {0}", i); 196 gfx.FillRectangle(brush, 0, 0, 256, 256);
194
195 // Create a solid color texture for this layer
196 detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
197 using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
198 {
199 using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
200 gfx.FillRectangle(brush, 0, 0, 256, 256);
201 }
202 } 197 }
203 } 198 }
204 199 else
205 #region Layer Map
206
207 float[] layermap = new float[256 * 256];
208
209 for (int y = 0; y < 256; y++)
210 { 200 {
211 for (int x = 0; x < 256; x++) 201 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
212 { 202 {
213 float height = heightmap[y * 256 + x]; 203 detailTexture[i] = ResizeBitmap(detailTexture[i], 256, 256);
214
215 float pctX = (float)x / 255f;
216 float pctY = (float)y / 255f;
217
218 // Use bilinear interpolation between the four corners of start height and
219 // height range to select the current values at this position
220 float startHeight = ImageUtils.Bilinear(
221 startHeights[0],
222 startHeights[2],
223 startHeights[1],
224 startHeights[3],
225 pctX, pctY);
226 startHeight = Utils.Clamp(startHeight, 0f, 255f);
227
228 float heightRange = ImageUtils.Bilinear(
229 heightRanges[0],
230 heightRanges[2],
231 heightRanges[1],
232 heightRanges[3],
233 pctX, pctY);
234 heightRange = Utils.Clamp(heightRange, 0f, 255f);
235
236 // Generate two frequencies of perlin noise based on our global position
237 // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
238 Vector3 vec = new Vector3
239 (
240 ((float)regionPosition.X + x) * 0.20319f,
241 ((float)regionPosition.Y + y) * 0.20319f,
242 height * 0.25f
243 );
244
245 float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
246 float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
247 float noise = (lowFreq + highFreq) * 2f;
248
249 // Combine the current height, generated noise, start height, and height range parameters, then scale all of it
250 float layer = ((height + noise - startHeight) / heightRange) * 4f;
251 if (Single.IsNaN(layer)) layer = 0f;
252 layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f);
253 } 204 }
254 } 205 }
255 206 }
256 #endregion Layer Map 207
257 208 #region Layer Map
258 #region Texture Compositing 209
259 210 float[,] layermap = new float[256, 256];
260 output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); 211
261 outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); 212 // Scale difference between actual region size and the 256 texture being created
262 213 int xFactor = terrain.Width / 256;
263 unsafe 214 int yFactor = terrain.Height / 256;
215
216 // Create 'layermap' where each value is the fractional layer number to place
217 // at that point. For instance, a value of 1.345 gives the blending of
218 // layer 1 and layer 2 for that point.
219 for (int y = 0; y < 256; y++)
220 {
221 for (int x = 0; x < 256; x++)
264 { 222 {
265 // Get handles to all of the texture data arrays 223 float height = (float)terrain[x * xFactor, y * yFactor];
266 BitmapData[] datas = new BitmapData[] 224
267 { 225 float pctX = (float)x / 255f;
268 detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), 226 float pctY = (float)y / 255f;
269 detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), 227
270 detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), 228 // Use bilinear interpolation between the four corners of start height and
271 detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) 229 // height range to select the current values at this position
272 }; 230 float startHeight = ImageUtils.Bilinear(
273 231 startHeights[0],
274 int[] comps = new int[] 232 startHeights[2],
275 { 233 startHeights[1],
276 (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, 234 startHeights[3],
277 (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, 235 pctX, pctY);
278 (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, 236 startHeight = Utils.Clamp(startHeight, 0f, 255f);
279 (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 237
280 }; 238 float heightRange = ImageUtils.Bilinear(
281 239 heightRanges[0],
282 for (int y = 0; y < 256; y++) 240 heightRanges[2],
283 { 241 heightRanges[1],
284 for (int x = 0; x < 256; x++) 242 heightRanges[3],
285 { 243 pctX, pctY);
286 float layer = layermap[y * 256 + x]; 244 heightRange = Utils.Clamp(heightRange, 0f, 255f);
287 245
288 // Select two textures 246 // Generate two frequencies of perlin noise based on our global position
289 int l0 = (int)Math.Floor(layer); 247 // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
290 int l1 = Math.Min(l0 + 1, 3); 248 Vector3 vec = new Vector3
291 249 (
292 byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; 250 ((float)regionPosition.X + (x * xFactor)) * 0.20319f,
293 byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; 251 ((float)regionPosition.Y + (y * yFactor)) * 0.20319f,
294 byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; 252 height * 0.25f
295 253 );
296 float aB = *(ptrA + 0); 254
297 float aG = *(ptrA + 1); 255 float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
298 float aR = *(ptrA + 2); 256 float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
299 257 float noise = (lowFreq + highFreq) * 2f;
300 float bB = *(ptrB + 0); 258
301 float bG = *(ptrB + 1); 259 // Combine the current height, generated noise, start height, and height range parameters, then scale all of it
302 float bR = *(ptrB + 2); 260 float layer = ((height + noise - startHeight) / heightRange) * 4f;
303 261 if (Single.IsNaN(layer))
304 float layerDiff = layer - l0; 262 layer = 0f;
305 263 layermap[x, y] = Utils.Clamp(layer, 0f, 3f);
306 // Interpolate between the two selected textures
307 *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
308 *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
309 *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
310 }
311 }
312
313 for (int i = 0; i < 4; i++)
314 detailTexture[i].UnlockBits(datas[i]);
315 } 264 }
316 } 265 }
317 finally 266
267 #endregion Layer Map
268
269 #region Texture Compositing
270
271 Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
272 BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
273
274 // Unsafe work as we lock down the source textures for quicker access and access the
275 // pixel data directly
276 unsafe
318 { 277 {
319 for (int i = 0; i < 4; i++) 278 // Get handles to all of the texture data arrays
320 if (detailTexture[i] != null) 279 BitmapData[] datas = new BitmapData[]
321 detailTexture[i].Dispose(); 280 {
281 detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
282 detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
283 detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
284 detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
285 };
286
287 // Compute size of each pixel data (used to address into the pixel data array)
288 int[] comps = new int[]
289 {
290 (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
291 (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
292 (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
293 (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
294 };
295
296 for (int y = 0; y < 256; y++)
297 {
298 for (int x = 0; x < 256; x++)
299 {
300 float layer = layermap[x, y];
301
302 // Select two textures
303 int l0 = (int)Math.Floor(layer);
304 int l1 = Math.Min(l0 + 1, 3);
305
306 byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
307 byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
308 byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;
309
310 float aB = *(ptrA + 0);
311 float aG = *(ptrA + 1);
312 float aR = *(ptrA + 2);
313
314 float bB = *(ptrB + 0);
315 float bG = *(ptrB + 1);
316 float bR = *(ptrB + 2);
317
318 float layerDiff = layer - l0;
319
320 // Interpolate between the two selected textures
321 *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
322 *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
323 *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
324 }
325 }
326
327 for (int i = 0; i < detailTexture.Length; i++)
328 detailTexture[i].UnlockBits(datas[i]);
322 } 329 }
323 330
331 for (int i = 0; i < detailTexture.Length; i++)
332 if (detailTexture[i] != null)
333 detailTexture[i].Dispose();
334
324 output.UnlockBits(outputData); 335 output.UnlockBits(outputData);
325 336
326 // We generated the texture upside down, so flip it 337 // We generated the texture upside down, so flip it
@@ -331,6 +342,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
331 return output; 342 return output;
332 } 343 }
333 344
345 public static Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
346 {
347 m_log.DebugFormat("{0} ResizeBitmap. From <{1},{2}> to <{3},{4}>",
348 LogHeader, b.Width, b.Height, nWidth, nHeight);
349 Bitmap result = new Bitmap(nWidth, nHeight);
350 using (Graphics g = Graphics.FromImage(result))
351 g.DrawImage(b, 0, 0, nWidth, nHeight);
352 b.Dispose();
353 return result;
354 }
355
334 public static Bitmap SplatSimple(float[] heightmap) 356 public static Bitmap SplatSimple(float[] heightmap)
335 { 357 {
336 const float BASE_HSV_H = 93f / 360f; 358 const float BASE_HSV_H = 93f / 360f;
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
index 5e0dfa7..5f2534b 100644
--- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
@@ -31,21 +31,25 @@ using System.Drawing;
31using System.Drawing.Imaging; 31using System.Drawing.Imaging;
32using System.IO; 32using System.IO;
33using System.Reflection; 33using System.Reflection;
34
34using CSJ2K; 35using CSJ2K;
35using Nini.Config; 36using Nini.Config;
36using log4net; 37using log4net;
37using Rednettle.Warp3D; 38using Rednettle.Warp3D;
38using Mono.Addins; 39using Mono.Addins;
39using OpenMetaverse; 40
40using OpenMetaverse.Imaging;
41using OpenMetaverse.Rendering;
42using OpenMetaverse.StructuredData;
43using OpenSim.Framework; 41using OpenSim.Framework;
44using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.Physics.Manager; 44using OpenSim.Region.PhysicsModules.SharedBase;
47using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
48 46
47using OpenMetaverse;
48using OpenMetaverse.Assets;
49using OpenMetaverse.Imaging;
50using OpenMetaverse.Rendering;
51using OpenMetaverse.StructuredData;
52
49using WarpRenderer = global::Warp3D.Warp3D; 53using WarpRenderer = global::Warp3D.Warp3D;
50 54
51namespace OpenSim.Region.CoreModules.World.Warp3DMap 55namespace OpenSim.Region.CoreModules.World.Warp3DMap
@@ -58,11 +62,22 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
58 62
59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 63 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 64
65#pragma warning disable 414
66 private static string LogHeader = "[WARP 3D IMAGE MODULE]";
67#pragma warning restore 414
68
61 private Scene m_scene; 69 private Scene m_scene;
62 private IRendering m_primMesher; 70 private IRendering m_primMesher;
63 private IConfigSource m_config;
64 private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>(); 71 private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>();
65 private bool m_useAntiAliasing = false; // TODO: Make this a config option 72
73 private IConfigSource m_config;
74 private bool m_drawPrimVolume = true; // true if should render the prims on the tile
75 private bool m_textureTerrain = true; // true if to create terrain splatting texture
76 private bool m_texturePrims = true; // true if should texture the rendered prims
77 private float m_texturePrimSize = 48f; // size of prim before we consider texturing it
78 private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes
79 private bool m_useAntiAliasing = false; // true if to anti-alias the rendered image
80
66 private bool m_Enabled = false; 81 private bool m_Enabled = false;
67 82
68 #region Region Module interface 83 #region Region Module interface
@@ -71,11 +86,27 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
71 { 86 {
72 m_config = source; 87 m_config = source;
73 88
74 IConfig startupConfig = m_config.Configs["Startup"]; 89 string[] configSections = new string[] { "Map", "Startup" };
75 if (startupConfig.GetString("MapImageModule", "MapImageModule") != "Warp3DImageModule") 90
91 if (Util.GetConfigVarFromSections<string>(
92 m_config, "MapImageModule", configSections, "MapImageModule") != "Warp3DImageModule")
76 return; 93 return;
77 94
78 m_Enabled = true; 95 m_Enabled = true;
96
97 m_drawPrimVolume
98 = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume);
99 m_textureTerrain
100 = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, m_textureTerrain);
101 m_texturePrims
102 = Util.GetConfigVarFromSections<bool>(m_config, "TexturePrims", configSections, m_texturePrims);
103 m_texturePrimSize
104 = Util.GetConfigVarFromSections<float>(m_config, "TexturePrimSize", configSections, m_texturePrimSize);
105 m_renderMeshes
106 = Util.GetConfigVarFromSections<bool>(m_config, "RenderMeshes", configSections, m_renderMeshes);
107 m_useAntiAliasing
108 = Util.GetConfigVarFromSections<bool>(m_config, "UseAntiAliasing", configSections, m_useAntiAliasing);
109
79 } 110 }
80 111
81 public void AddRegion(Scene scene) 112 public void AddRegion(Scene scene)
@@ -127,33 +158,28 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
127 158
128 public Bitmap CreateMapTile() 159 public Bitmap CreateMapTile()
129 { 160 {
130 Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f); 161 // Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f);
131 Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, (int)Constants.RegionSize, (int)Constants.RegionSize, (float)Constants.RegionSize, (float)Constants.RegionSize); 162 // Camera above the middle of the region
163 Vector3 camPos = new Vector3(
164 m_scene.RegionInfo.RegionSizeX/2 - 0.5f,
165 m_scene.RegionInfo.RegionSizeY/2 - 0.5f,
166 221.7025033688163f);
167 // Viewport viewing down onto the region
168 Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f,
169 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY,
170 (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY );
171 // Fill the viewport and return the image
132 return CreateMapTile(viewport, false); 172 return CreateMapTile(viewport, false);
133 } 173 }
134 174
135 public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) 175 public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures)
136 { 176 {
137 Viewport viewport = new Viewport(camPos, camDir, fov, (float)Constants.RegionSize, 0.1f, width, height); 177 Viewport viewport = new Viewport(camPos, camDir, fov, Constants.RegionSize, 0.1f, width, height);
138 return CreateMapTile(viewport, useTextures); 178 return CreateMapTile(viewport, useTextures);
139 } 179 }
140 180
141 public Bitmap CreateMapTile(Viewport viewport, bool useTextures) 181 public Bitmap CreateMapTile(Viewport viewport, bool useTextures)
142 { 182 {
143 bool drawPrimVolume = true;
144 bool textureTerrain = true;
145
146 try
147 {
148 IConfig startupConfig = m_config.Configs["Startup"];
149 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume);
150 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain);
151 }
152 catch
153 {
154 m_log.Warn("[WARP 3D IMAGE MODULE]: Failed to load StartupConfig");
155 }
156
157 m_colors.Clear(); 183 m_colors.Clear();
158 184
159 int width = viewport.Width; 185 int width = viewport.Width;
@@ -166,6 +192,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
166 } 192 }
167 193
168 WarpRenderer renderer = new WarpRenderer(); 194 WarpRenderer renderer = new WarpRenderer();
195
169 renderer.CreateScene(width, height); 196 renderer.CreateScene(width, height);
170 renderer.Scene.autoCalcNormals = false; 197 renderer.Scene.autoCalcNormals = false;
171 198
@@ -197,8 +224,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
197 renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40)); 224 renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40));
198 225
199 CreateWater(renderer); 226 CreateWater(renderer);
200 CreateTerrain(renderer, textureTerrain); 227 CreateTerrain(renderer, m_textureTerrain);
201 if (drawPrimVolume) 228 if (m_drawPrimVolume)
202 CreateAllPrims(renderer, useTextures); 229 CreateAllPrims(renderer, useTextures);
203 230
204 renderer.Render(); 231 renderer.Render();
@@ -214,6 +241,18 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
214 // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory 241 // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory
215 // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating 242 // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating
216 // this map tile simply takes a lot of memory. 243 // this map tile simply takes a lot of memory.
244 foreach (var o in renderer.Scene.objectData.Values)
245 {
246 warp_Object obj = (warp_Object)o;
247 obj.vertexData = null;
248 obj.triangleData = null;
249 }
250
251 renderer.Scene.removeAllObjects();
252 renderer = null;
253 viewport = null;
254
255 m_colors.Clear();
217 GC.Collect(); 256 GC.Collect();
218 m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()"); 257 m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()");
219 258
@@ -240,61 +279,74 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
240 279
241 #region Rendering Methods 280 #region Rendering Methods
242 281
282 // Add a water plane to the renderer.
243 private void CreateWater(WarpRenderer renderer) 283 private void CreateWater(WarpRenderer renderer)
244 { 284 {
245 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; 285 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
246 286
247 renderer.AddPlane("Water", 256f * 0.5f); 287 renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f);
248 renderer.Scene.sceneobject("Water").setPos(127.5f, waterHeight, 127.5f); 288 renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX/2 - 0.5f,
289 waterHeight,
290 m_scene.RegionInfo.RegionSizeY/2 - 0.5f );
249 291
250 renderer.AddMaterial("WaterColor", ConvertColor(WATER_COLOR)); 292 warp_Material waterColorMaterial = new warp_Material(ConvertColor(WATER_COLOR));
251 renderer.Scene.material("WaterColor").setReflectivity(0); // match water color with standard map module thanks lkalif 293 waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif
252 renderer.Scene.material("WaterColor").setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); 294 waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f));
295 renderer.Scene.addMaterial("WaterColor", waterColorMaterial);
253 renderer.SetObjectMaterial("Water", "WaterColor"); 296 renderer.SetObjectMaterial("Water", "WaterColor");
254 } 297 }
255 298
299 // Add a terrain to the renderer.
300 // Note that we create a 'low resolution' 256x256 vertex terrain rather than trying for
301 // full resolution. This saves a lot of memory especially for very large regions.
256 private void CreateTerrain(WarpRenderer renderer, bool textureTerrain) 302 private void CreateTerrain(WarpRenderer renderer, bool textureTerrain)
257 { 303 {
258 ITerrainChannel terrain = m_scene.Heightmap; 304 ITerrainChannel terrain = m_scene.Heightmap;
259 float[] heightmap = terrain.GetFloatsSerialised(); 305
306 // 'diff' is the difference in scale between the real region size and the size of terrain we're buiding
307 float diff = (float)m_scene.RegionInfo.RegionSizeX / 256f;
260 308
261 warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2); 309 warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2);
262 310
263 for (int y = 0; y < 256; y++) 311 // Create all the vertices for the terrain
312 for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
264 { 313 {
265 for (int x = 0; x < 256; x++) 314 for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
266 { 315 {
267 int v = y * 256 + x; 316 warp_Vector pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]);
268 float height = heightmap[v]; 317 obj.addVertex(new warp_Vertex(pos,
269 318 x / (float)m_scene.RegionInfo.RegionSizeX,
270 warp_Vector pos = ConvertVector(new Vector3(x, y, height)); 319 (((float)m_scene.RegionInfo.RegionSizeY) - y) / m_scene.RegionInfo.RegionSizeY) );
271 obj.addVertex(new warp_Vertex(pos, (float)x / 255f, (float)(255 - y) / 255f));
272 } 320 }
273 } 321 }
274 322
275 for (int y = 0; y < 256; y++) 323 // Now that we have all the vertices, make another pass and create
324 // the normals for each of the surface triangles and
325 // create the list of triangle indices.
326 for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
276 { 327 {
277 for (int x = 0; x < 256; x++) 328 for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
278 { 329 {
279 if (x < 255 && y < 255) 330 float newX = x / diff;
331 float newY = y / diff;
332 if (newX < 255 && newY < 255)
280 { 333 {
281 int v = y * 256 + x; 334 int v = (int)newY * 256 + (int)newX;
282 335
283 // Normal 336 // Normal for a triangle made up of three adjacent vertices
284 Vector3 v1 = new Vector3(x, y, heightmap[y * 256 + x]); 337 Vector3 v1 = new Vector3(newX, newY, (float)terrain[(int)x, (int)y]);
285 Vector3 v2 = new Vector3(x + 1, y, heightmap[y * 256 + x + 1]); 338 Vector3 v2 = new Vector3(newX + 1, newY, (float)terrain[(int)(x + 1), (int)y]);
286 Vector3 v3 = new Vector3(x, y + 1, heightmap[(y + 1) * 256 + x]); 339 Vector3 v3 = new Vector3(newX, newY + 1, (float)terrain[(int)x, ((int)(y + 1))]);
287 warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3)); 340 warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3));
288 norm = norm.reverse(); 341 norm = norm.reverse();
289 obj.vertex(v).n = norm; 342 obj.vertex(v).n = norm;
290 343
291 // Triangle 1 344 // Make two triangles for each of the squares in the grid of vertices
292 obj.addTriangle( 345 obj.addTriangle(
293 v, 346 v,
294 v + 1, 347 v + 1,
295 v + 256); 348 v + 256);
296 349
297 // Triangle 2
298 obj.addTriangle( 350 obj.addTriangle(
299 v + 256 + 1, 351 v + 256 + 1,
300 v + 256, 352 v + 256,
@@ -309,7 +361,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
309 float[] startHeights = new float[4]; 361 float[] startHeights = new float[4];
310 float[] heightRanges = new float[4]; 362 float[] heightRanges = new float[4];
311 363
312 RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings; 364 OpenSim.Framework.RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;
313 365
314 textureIDs[0] = regionInfo.TerrainTexture1; 366 textureIDs[0] = regionInfo.TerrainTexture1;
315 textureIDs[1] = regionInfo.TerrainTexture2; 367 textureIDs[1] = regionInfo.TerrainTexture2;
@@ -327,14 +379,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
327 heightRanges[3] = (float)regionInfo.Elevation2NE; 379 heightRanges[3] = (float)regionInfo.Elevation2NE;
328 380
329 uint globalX, globalY; 381 uint globalX, globalY;
330 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); 382 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);
331 383
332 warp_Texture texture; 384 warp_Texture texture;
333
334 using ( 385 using (
335 Bitmap image 386 Bitmap image
336 = TerrainSplat.Splat( 387 = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges,
337 heightmap, textureIDs, startHeights, heightRanges,
338 new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) 388 new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain))
339 { 389 {
340 texture = new warp_Texture(image); 390 texture = new warp_Texture(image);
@@ -355,7 +405,6 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
355 m_scene.ForEachSOG( 405 m_scene.ForEachSOG(
356 delegate(SceneObjectGroup group) 406 delegate(SceneObjectGroup group)
357 { 407 {
358 CreatePrim(renderer, group.RootPart, useTextures);
359 foreach (SceneObjectPart child in group.Parts) 408 foreach (SceneObjectPart child in group.Parts)
360 CreatePrim(renderer, child, useTextures); 409 CreatePrim(renderer, child, useTextures);
361 } 410 }
@@ -372,8 +421,48 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
372 if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE) 421 if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE)
373 return; 422 return;
374 423
424 FacetedMesh renderMesh = null;
375 Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); 425 Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset);
376 FacetedMesh renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); 426
427 if (m_renderMeshes)
428 {
429 if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero)
430 {
431 // Try fetchinng the asset
432 byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
433 if (sculptAsset != null)
434 {
435 // Is it a mesh?
436 if (omvPrim.Sculpt.Type == SculptType.Mesh)
437 {
438 AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
439 FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
440 meshAsset = null;
441 }
442 else // It's sculptie
443 {
444 IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
445 if (imgDecoder != null)
446 {
447 Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
448 if (sculpt != null)
449 {
450 renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt,
451 DetailLevel.Medium);
452 sculpt.Dispose();
453 }
454 }
455 }
456 }
457 }
458 }
459
460 // If not a mesh or sculptie, try the regular mesher
461 if (renderMesh == null)
462 {
463 renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
464 }
465
377 if (renderMesh == null) 466 if (renderMesh == null)
378 return; 467 return;
379 468
@@ -432,7 +521,11 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
432 521
433 Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); 522 Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
434 Color4 faceColor = GetFaceColor(teFace); 523 Color4 faceColor = GetFaceColor(teFace);
435 string materialName = GetOrCreateMaterial(renderer, faceColor); 524 string materialName = String.Empty;
525 if (m_texturePrims && prim.Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize)
526 materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID);
527 else
528 materialName = GetOrCreateMaterial(renderer, faceColor);
436 529
437 faceObj.transform(m); 530 faceObj.transform(m);
438 faceObj.setPos(primPos); 531 faceObj.setPos(primPos);
@@ -521,10 +614,59 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
521 return name; 614 return name;
522 } 615 }
523 616
617 public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID)
618 {
619 string materialName = "Color-" + faceColor.ToString() + "-Texture-" + textureID.ToString();
620
621 if (renderer.Scene.material(materialName) == null)
622 {
623 renderer.AddMaterial(materialName, ConvertColor(faceColor));
624 if (faceColor.A < 1f)
625 {
626 renderer.Scene.material(materialName).setTransparency((byte) ((1f - faceColor.A)*255f));
627 }
628 warp_Texture texture = GetTexture(textureID);
629 if (texture != null)
630 renderer.Scene.material(materialName).setTexture(texture);
631 }
632
633 return materialName;
634 }
635
636 private warp_Texture GetTexture(UUID id)
637 {
638 warp_Texture ret = null;
639
640 byte[] asset = m_scene.AssetService.GetData(id.ToString());
641
642 if (asset != null)
643 {
644 IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
645
646 try
647 {
648 using (Bitmap img = (Bitmap)imgDecoder.DecodeToImage(asset))
649 ret = new warp_Texture(img);
650 }
651 catch (Exception e)
652 {
653 m_log.Warn(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id), e);
654 }
655 }
656
657 return ret;
658 }
659
524 #endregion Rendering Methods 660 #endregion Rendering Methods
525 661
526 #region Static Helpers 662 #region Static Helpers
527 663
664 // Note: axis change.
665 private static warp_Vector ConvertVector(float x, float y, float z)
666 {
667 return new warp_Vector(x, z, y);
668 }
669
528 private static warp_Vector ConvertVector(Vector3 vector) 670 private static warp_Vector ConvertVector(Vector3 vector)
529 { 671 {
530 return new warp_Vector(vector.X, vector.Z, vector.Y); 672 return new warp_Vector(vector.X, vector.Z, vector.Y);
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
index 9de588c..35014f5 100644
--- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
+++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
@@ -216,13 +216,13 @@ namespace OpenSim.Region.CoreModules
216 // FIXME: If console region is root then this will be printed by every module. Currently, there is no 216 // FIXME: If console region is root then this will be printed by every module. Currently, there is no
217 // way to prevent this, short of making the entire module shared (which is complete overkill). 217 // way to prevent this, short of making the entire module shared (which is complete overkill).
218 // One possibility is to return a bool to signal whether the module has completely handled the command 218 // One possibility is to return a bool to signal whether the module has completely handled the command
219 m_log.InfoFormat("[WIND]: Please change to a specific region in order to set Sun parameters."); 219 MainConsole.Instance.Output("Please change to a specific region in order to set Sun parameters.");
220 return; 220 return;
221 } 221 }
222 222
223 if (m_scene.ConsoleScene() != m_scene) 223 if (m_scene.ConsoleScene() != m_scene)
224 { 224 {
225 m_log.InfoFormat("[WIND]: Console Scene is not my scene."); 225 MainConsole.Instance.Output("Console Scene is not my scene.");
226 return; 226 return;
227 } 227 }
228 } 228 }
@@ -233,7 +233,9 @@ namespace OpenSim.Region.CoreModules
233 private void HandleConsoleCommand(string module, string[] cmdparams) 233 private void HandleConsoleCommand(string module, string[] cmdparams)
234 { 234 {
235 ValidateConsole(); 235 ValidateConsole();
236 m_log.Info("[WIND] The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins."); 236
237 MainConsole.Instance.Output(
238 "The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins.");
237 } 239 }
238 240
239 /// <summary> 241 /// <summary>
@@ -246,7 +248,9 @@ namespace OpenSim.Region.CoreModules
246 if ((cmdparams.Length != 4) 248 if ((cmdparams.Length != 4)
247 || !cmdparams[1].Equals("base")) 249 || !cmdparams[1].Equals("base"))
248 { 250 {
249 m_log.Info("[WIND] Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>"); 251 MainConsole.Instance.Output(
252 "Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>");
253
250 return; 254 return;
251 } 255 }
252 256
@@ -261,7 +265,9 @@ namespace OpenSim.Region.CoreModules
261 } 265 }
262 else 266 else
263 { 267 {
264 m_log.InfoFormat("[WIND] Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]); 268 MainConsole.Instance.OutputFormat(
269 "Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]);
270
265 return; 271 return;
266 } 272 }
267 273
@@ -271,22 +277,23 @@ namespace OpenSim.Region.CoreModules
271 277
272 if (desiredPlugin.Equals(m_activeWindPlugin.Name)) 278 if (desiredPlugin.Equals(m_activeWindPlugin.Name))
273 { 279 {
274 m_log.InfoFormat("[WIND] Wind model plugin {0} is already active", cmdparams[3]); 280 MainConsole.Instance.OutputFormat("Wind model plugin {0} is already active", cmdparams[3]);
281
275 return; 282 return;
276 } 283 }
277 284
278 if (m_availableWindPlugins.ContainsKey(desiredPlugin)) 285 if (m_availableWindPlugins.ContainsKey(desiredPlugin))
279 { 286 {
280 m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]]; 287 m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]];
281 m_log.InfoFormat("[WIND] {0} wind model plugin now active", m_activeWindPlugin.Name); 288
289 MainConsole.Instance.OutputFormat("{0} wind model plugin now active", m_activeWindPlugin.Name);
282 } 290 }
283 else 291 else
284 { 292 {
285 m_log.InfoFormat("[WIND] Could not find wind model plugin {0}", desiredPlugin); 293 MainConsole.Instance.OutputFormat("Could not find wind model plugin {0}", desiredPlugin);
286 } 294 }
287 break; 295 break;
288 } 296 }
289
290 } 297 }
291 298
292 /// <summary> 299 /// <summary>
@@ -300,7 +307,7 @@ namespace OpenSim.Region.CoreModules
300 if ((cmdparams.Length != 4) 307 if ((cmdparams.Length != 4)
301 && (cmdparams.Length != 3)) 308 && (cmdparams.Length != 3))
302 { 309 {
303 m_log.Info("[WIND] Usage: wind <plugin> <param> [value]"); 310 MainConsole.Instance.Output("Usage: wind <plugin> <param> [value]");
304 return; 311 return;
305 } 312 }
306 313
@@ -311,16 +318,17 @@ namespace OpenSim.Region.CoreModules
311 { 318 {
312 if (!float.TryParse(cmdparams[3], out value)) 319 if (!float.TryParse(cmdparams[3], out value))
313 { 320 {
314 m_log.InfoFormat("[WIND] Invalid value {0}", cmdparams[3]); 321 MainConsole.Instance.OutputFormat("Invalid value {0}", cmdparams[3]);
315 } 322 }
316 323
317 try 324 try
318 { 325 {
319 WindParamSet(plugin, param, value); 326 WindParamSet(plugin, param, value);
327 MainConsole.Instance.OutputFormat("{0} set to {1}", param, value);
320 } 328 }
321 catch (Exception e) 329 catch (Exception e)
322 { 330 {
323 m_log.InfoFormat("[WIND] {0}", e.Message); 331 MainConsole.Instance.OutputFormat("{0}", e.Message);
324 } 332 }
325 } 333 }
326 else 334 else
@@ -328,11 +336,11 @@ namespace OpenSim.Region.CoreModules
328 try 336 try
329 { 337 {
330 value = WindParamGet(plugin, param); 338 value = WindParamGet(plugin, param);
331 m_log.InfoFormat("[WIND] {0} : {1}", param, value); 339 MainConsole.Instance.OutputFormat("{0} : {1}", param, value);
332 } 340 }
333 catch (Exception e) 341 catch (Exception e)
334 { 342 {
335 m_log.InfoFormat("[WIND] {0}", e.Message); 343 MainConsole.Instance.OutputFormat("{0}", e.Message);
336 } 344 }
337 } 345 }
338 346
@@ -366,13 +374,11 @@ namespace OpenSim.Region.CoreModules
366 { 374 {
367 IWindModelPlugin windPlugin = m_availableWindPlugins[plugin]; 375 IWindModelPlugin windPlugin = m_availableWindPlugins[plugin];
368 windPlugin.WindParamSet(param, value); 376 windPlugin.WindParamSet(param, value);
369 m_log.InfoFormat("[WIND] {0} set to {1}", param, value);
370 } 377 }
371 else 378 else
372 { 379 {
373 throw new Exception(String.Format("Could not find plugin {0}", plugin)); 380 throw new Exception(String.Format("Could not find plugin {0}", plugin));
374 } 381 }
375
376 } 382 }
377 383
378 public float WindParamGet(string plugin, string param) 384 public float WindParamGet(string plugin, string param)
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
index 708a9a2..d862f18 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -49,6 +49,18 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
49 List<Scene> m_scenes = new List<Scene>(); 49 List<Scene> m_scenes = new List<Scene>();
50 List<UUID> m_Clients; 50 List<UUID> m_Clients;
51 51
52 IWorldMapModule m_WorldMap;
53 IWorldMapModule WorldMap
54 {
55 get
56 {
57 if (m_WorldMap == null)
58 m_WorldMap = m_scene.RequestModuleInterface<IWorldMapModule>();
59 return m_WorldMap;
60 }
61
62 }
63
52 #region ISharedRegionModule Members 64 #region ISharedRegionModule Members
53 public void Initialise(IConfigSource source) 65 public void Initialise(IConfigSource source)
54 { 66 {
@@ -64,6 +76,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
64 m_scenes.Add(scene); 76 m_scenes.Add(scene);
65 scene.EventManager.OnNewClient += OnNewClient; 77 scene.EventManager.OnNewClient += OnNewClient;
66 m_Clients = new List<UUID>(); 78 m_Clients = new List<UUID>();
79
67 } 80 }
68 81
69 public void RemoveRegion(Scene scene) 82 public void RemoveRegion(Scene scene)
@@ -129,7 +142,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
129 private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) 142 private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags)
130 { 143 {
131 List<MapBlockData> blocks = new List<MapBlockData>(); 144 List<MapBlockData> blocks = new List<MapBlockData>();
132 MapBlockData data;
133 if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) 145 if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4))
134 { 146 {
135 // final block, closing the search result 147 // final block, closing the search result
@@ -143,50 +155,51 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
143 } 155 }
144 156
145 157
146 //m_log.DebugFormat("MAP NAME=({0})", mapName); 158 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
147 159
148 // Hack to get around the fact that ll V3 now drops the port from the
149 // map name. See https://jira.secondlife.com/browse/VWR-28570
150 //
151 // Caller, use this magic form instead:
152 // secondlife://http|!!mygrid.com|8002|Region+Name/128/128
153 // or url encode if possible.
154 // the hacks we do with this viewer...
155 //
156 string mapNameOrig = mapName; 160 string mapNameOrig = mapName;
157 if (mapName.Contains("|")) 161 if (regionInfos.Count == 0)
158 mapName = mapName.Replace('|', ':'); 162 {
159 if (mapName.Contains("+")) 163 // Hack to get around the fact that ll V3 now drops the port from the
160 mapName = mapName.Replace('+', ' '); 164 // map name. See https://jira.secondlife.com/browse/VWR-28570
161 if (mapName.Contains("!")) 165 //
162 mapName = mapName.Replace('!', '/'); 166 // Caller, use this magic form instead:
167 // secondlife://http|!!mygrid.com|8002|Region+Name/128/128
168 // or url encode if possible.
169 // the hacks we do with this viewer...
170 //
171 if (mapName.Contains("|"))
172 mapName = mapName.Replace('|', ':');
173 if (mapName.Contains("+"))
174 mapName = mapName.Replace('+', ' ');
175 if (mapName.Contains("!"))
176 mapName = mapName.Replace('!', '/');
177
178 if (mapName != mapNameOrig)
179 regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
180 }
163 181
164 // try to fetch from GridServer
165 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
166
167 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); 182 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags);
183
168 if (regionInfos.Count > 0) 184 if (regionInfos.Count > 0)
169 { 185 {
170 foreach (GridRegion info in regionInfos) 186 foreach (GridRegion info in regionInfos)
171 { 187 {
172 data = new MapBlockData(); 188 if ((flags & 2) == 2) // V2 sends this
173 data.Agents = 0; 189 {
174 data.Access = info.Access; 190 List<MapBlockData> datas = WorldMap.Map2BlockFromGridRegion(info, flags);
175 if (flags == 2) // V2 sends this 191 // ugh! V2-3 is very sensitive about the result being
176 data.MapImageId = UUID.Zero; 192 // exactly the same as the requested name
177 else 193 if (regionInfos.Count == 1 && (mapName != mapNameOrig))
178 data.MapImageId = info.TerrainImage; 194 datas.ForEach(d => d.Name = mapNameOrig);
179 // ugh! V2-3 is very sensitive about the result being 195
180 // exactly the same as the requested name 196 blocks.AddRange(datas);
181 if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) 197 }
182 data.Name = mapNameOrig;
183 else 198 else
184 data.Name = info.RegionName; 199 {
185 data.RegionFlags = 0; // TODO not used? 200 MapBlockData data = WorldMap.MapBlockFromGridRegion(info, flags);
186 data.WaterHeight = 0; // not used 201 blocks.Add(data);
187 data.X = (ushort)(info.RegionLocX / Constants.RegionSize); 202 }
188 data.Y = (ushort)(info.RegionLocY / Constants.RegionSize);
189 blocks.Add(data);
190 } 203 }
191 } 204 }
192 205
@@ -204,8 +217,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
204 { 217 {
205 if (regionInfos.Count == 0) 218 if (regionInfos.Count == 0)
206 remoteClient.SendAlertMessage("No regions found with that name."); 219 remoteClient.SendAlertMessage("No regions found with that name.");
207 else if (regionInfos.Count == 1) 220 // this seems unnecessary because found regions will show up in the search results
208 remoteClient.SendAlertMessage("Region found!"); 221 //else if (regionInfos.Count == 1)
222 // remoteClient.SendAlertMessage("Region found!");
209 } 223 }
210 } 224 }
211 225
@@ -214,7 +228,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
214 // final block, closing the search result 228 // final block, closing the search result
215 MapBlockData data = new MapBlockData(); 229 MapBlockData data = new MapBlockData();
216 data.Agents = 0; 230 data.Agents = 0;
217 data.Access = 255; 231 data.Access = (byte)SimAccess.NonExistent;
218 data.MapImageId = UUID.Zero; 232 data.MapImageId = UUID.Zero;
219 data.Name = ""; 233 data.Name = "";
220 data.RegionFlags = 0; 234 data.RegionFlags = 0;
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index e2f525c..db1187e 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -59,13 +59,18 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
59 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")] 59 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")]
60 public class WorldMapModule : INonSharedRegionModule, IWorldMapModule 60 public class WorldMapModule : INonSharedRegionModule, IWorldMapModule
61 { 61 {
62 private static readonly ILog m_log = 62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 63#pragma warning disable 414
64 private static string LogHeader = "[WORLD MAP]";
65#pragma warning restore 414
64 66
65 private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg"; 67 private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg";
66 private static readonly UUID STOP_UUID = UUID.Random(); 68 private static readonly UUID STOP_UUID = UUID.Random();
67 private static readonly string m_mapLayerPath = "0001/"; 69 private static readonly string m_mapLayerPath = "0001/";
68 70
71 private IMapImageGenerator m_mapImageGenerator;
72 private IMapImageUploadModule m_mapImageServiceModule;
73
69 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>(); 74 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
70 75
71 protected Scene m_scene; 76 protected Scene m_scene;
@@ -81,19 +86,24 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
81 private List<UUID> m_rootAgents = new List<UUID>(); 86 private List<UUID> m_rootAgents = new List<UUID>();
82 private volatile bool threadrunning = false; 87 private volatile bool threadrunning = false;
83 88
89 private IServiceThrottleModule m_ServiceThrottle;
90
84 //private int CacheRegionsDistance = 256; 91 //private int CacheRegionsDistance = 256;
85 92
86 #region INonSharedRegionModule Members 93 #region INonSharedRegionModule Members
87 public virtual void Initialise (IConfigSource config) 94 public virtual void Initialise (IConfigSource config)
88 { 95 {
89 IConfig startupConfig = config.Configs["Startup"]; 96 string[] configSections = new string[] { "Map", "Startup" };
90 if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap") 97
98 if (Util.GetConfigVarFromSections<string>(
99 config, "WorldMapModule", configSections, "WorldMap") == "WorldMap")
91 m_Enabled = true; 100 m_Enabled = true;
92 101
93 blacklistTimeout = startupConfig.GetInt("BlacklistTimeout", 10*60) * 1000; 102 blacklistTimeout
103 = Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000;
94 } 104 }
95 105
96 public virtual void AddRegion (Scene scene) 106 public virtual void AddRegion(Scene scene)
97 { 107 {
98 if (!m_Enabled) 108 if (!m_Enabled)
99 return; 109 return;
@@ -109,6 +119,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
109 "export-map [<path>]", 119 "export-map [<path>]",
110 "Save an image of the world map", HandleExportWorldMapConsoleCommand); 120 "Save an image of the world map", HandleExportWorldMapConsoleCommand);
111 121
122 m_scene.AddCommand(
123 "Regions", this, "generate map",
124 "generate map",
125 "Generates and stores a new maptile.", HandleGenerateMapConsoleCommand);
126
112 AddHandlers(); 127 AddHandlers();
113 } 128 }
114 } 129 }
@@ -128,8 +143,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
128 143
129 public virtual void RegionLoaded (Scene scene) 144 public virtual void RegionLoaded (Scene scene)
130 { 145 {
131 } 146 if (!m_Enabled)
147 return;
132 148
149 m_ServiceThrottle = scene.RequestModuleInterface<IServiceThrottleModule>();
150
151 m_mapImageGenerator = m_scene.RequestModuleInterface<IMapImageGenerator>();
152 m_mapImageServiceModule = m_scene.RequestModuleInterface<IMapImageUploadModule>();
153 }
133 154
134 public virtual void Close() 155 public virtual void Close()
135 { 156 {
@@ -156,7 +177,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
156 regionimage = regionimage.Replace("-", ""); 177 regionimage = regionimage.Replace("-", "");
157 m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage); 178 m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage);
158 179
159 MainServer.Instance.AddHTTPHandler(regionimage, OnHTTPGetMapImage); 180 MainServer.Instance.AddHTTPHandler(regionimage,
181 new GenericHTTPDOSProtector(OnHTTPGetMapImage, OnHTTPThrottled, new BasicDosProtectorOptions()
182 {
183 AllowXForwardedFor = false,
184 ForgetTimeSpan = TimeSpan.FromMinutes(2),
185 MaxRequestsInTimeframe = 4,
186 ReportingName = "MAPDOSPROTECTOR",
187 RequestTimeSpan = TimeSpan.FromSeconds(10),
188 ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
189 }).Process);
160 MainServer.Instance.AddLLSDHandler( 190 MainServer.Instance.AddLLSDHandler(
161 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest); 191 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
162 192
@@ -167,13 +197,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
167 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; 197 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
168 m_scene.EventManager.OnRegionUp += OnRegionUp; 198 m_scene.EventManager.OnRegionUp += OnRegionUp;
169 199
170 StartThread(new object()); 200// StartThread(new object());
171 } 201 }
172 202
173 // this has to be called with a lock on m_scene 203 // this has to be called with a lock on m_scene
174 protected virtual void RemoveHandlers() 204 protected virtual void RemoveHandlers()
175 { 205 {
176 StopThread(); 206// StopThread();
177 207
178 m_scene.EventManager.OnRegionUp -= OnRegionUp; 208 m_scene.EventManager.OnRegionUp -= OnRegionUp;
179 m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; 209 m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent;
@@ -259,15 +289,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
259 { 289 {
260 List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; 290 List<MapBlockData> mapBlocks = new List<MapBlockData>(); ;
261 291
292 // Get regions that are within 8 regions of here
262 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 293 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
263 (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, 294 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 8),
264 (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, 295 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 8),
265 (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, 296 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 8),
266 (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); 297 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 8) );
267 foreach (GridRegion r in regions) 298 foreach (GridRegion r in regions)
268 { 299 {
269 MapBlockData block = new MapBlockData(); 300 MapBlockData block = MapBlockFromGridRegion(r, 0);
270 MapBlockFromGridRegion(block, r, 0);
271 mapBlocks.Add(block); 301 mapBlocks.Add(block);
272 } 302 }
273 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); 303 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
@@ -351,7 +381,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
351 381
352// m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread"); 382// m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread");
353 383
354 Watchdog.StartThread( 384 WorkManager.StartThread(
355 process, 385 process,
356 string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName), 386 string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName),
357 ThreadPriority.BelowNormal, 387 ThreadPriority.BelowNormal,
@@ -387,24 +417,23 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
387 } 417 }
388 uint xstart = 0; 418 uint xstart = 0;
389 uint ystart = 0; 419 uint ystart = 0;
390 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); 420 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
391 if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) 421 if (itemtype == (int)GridItemType.AgentLocations)
392 { 422 {
393 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 423 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
394 { 424 {
395 // Local Map Item Request 425 // Just requesting map info about the current, local region
396 int tc = Environment.TickCount; 426 int tc = Environment.TickCount;
397 List<mapItemReply> mapitems = new List<mapItemReply>(); 427 List<mapItemReply> mapitems = new List<mapItemReply>();
398 mapItemReply mapitem = new mapItemReply(); 428 mapItemReply mapitem = new mapItemReply();
399 if (m_scene.GetRootAgentCount() <= 1) 429 if (m_scene.GetRootAgentCount() <= 1)
400 { 430 {
401 mapitem = new mapItemReply(); 431 mapitem = new mapItemReply(
402 mapitem.x = (uint)(xstart + 1); 432 xstart + 1,
403 mapitem.y = (uint)(ystart + 1); 433 ystart + 1,
404 mapitem.id = UUID.Zero; 434 UUID.Zero,
405 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()); 435 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
406 mapitem.Extra = 0; 436 0, 0);
407 mapitem.Extra2 = 0;
408 mapitems.Add(mapitem); 437 mapitems.Add(mapitem);
409 } 438 }
410 else 439 else
@@ -414,13 +443,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
414 // Don't send a green dot for yourself 443 // Don't send a green dot for yourself
415 if (sp.UUID != remoteClient.AgentId) 444 if (sp.UUID != remoteClient.AgentId)
416 { 445 {
417 mapitem = new mapItemReply(); 446 mapitem = new mapItemReply(
418 mapitem.x = (uint)(xstart + sp.AbsolutePosition.X); 447 xstart + (uint)sp.AbsolutePosition.X,
419 mapitem.y = (uint)(ystart + sp.AbsolutePosition.Y); 448 ystart + (uint)sp.AbsolutePosition.Y,
420 mapitem.id = UUID.Zero; 449 UUID.Zero,
421 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()); 450 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
422 mapitem.Extra = 1; 451 1, 0);
423 mapitem.Extra2 = 0;
424 mapitems.Add(mapitem); 452 mapitems.Add(mapitem);
425 } 453 }
426 }); 454 });
@@ -435,7 +463,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
435 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 463 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
436 } 464 }
437 } 465 }
438 else if (itemtype == 7) // Service 7 (MAP_ITEM_LAND_FOR_SALE) 466 else if (itemtype == (int)GridItemType.LandForSale) // Service 7 (MAP_ITEM_LAND_FOR_SALE)
439 { 467 {
440 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 468 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
441 { 469 {
@@ -465,14 +493,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
465 float x = (min.X+max.X)/2; 493 float x = (min.X+max.X)/2;
466 float y = (min.Y+max.Y)/2; 494 float y = (min.Y+max.Y)/2;
467 495
468 mapitem = new mapItemReply(); 496 mapitem = new mapItemReply(
469 mapitem.x = (uint)(xstart + x); 497 xstart + (uint)x,
470 mapitem.y = (uint)(ystart + y); 498 ystart + (uint)y,
471 // mapitem.z = (uint)m_scene.GetGroundHeight(x,y); 499 parcel.GlobalID,
472 mapitem.id = parcel.GlobalID; 500 parcel.Name,
473 mapitem.name = parcel.Name; 501 parcel.Area,
474 mapitem.Extra = parcel.Area; 502 parcel.SalePrice
475 mapitem.Extra2 = parcel.SalePrice; 503 );
476 mapitems.Add(mapitem); 504 mapitems.Add(mapitem);
477 } 505 }
478 } 506 }
@@ -487,7 +515,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
487 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 515 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
488 } 516 }
489 } 517 }
490 else if (itemtype == 1) // Service 1 (MAP_ITEM_TELEHUB) 518 else if (itemtype == (int)GridItemType.Telehub) // Service 1 (MAP_ITEM_TELEHUB)
491 { 519 {
492 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 520 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
493 { 521 {
@@ -497,13 +525,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
497 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); 525 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
498 if (sog != null) 526 if (sog != null)
499 { 527 {
500 mapitem = new mapItemReply(); 528 mapitem = new mapItemReply(
501 mapitem.x = (uint)(xstart + sog.AbsolutePosition.X); 529 xstart + (uint)sog.AbsolutePosition.X,
502 mapitem.y = (uint)(ystart + sog.AbsolutePosition.Y); 530 ystart + (uint)sog.AbsolutePosition.Y,
503 mapitem.id = UUID.Zero; 531 UUID.Zero,
504 mapitem.name = sog.Name; 532 sog.Name,
505 mapitem.Extra = 0; // color (not used) 533 0, // color (not used)
506 mapitem.Extra2 = 0; // 0 = telehub / 1 = infohub 534 0 // 0 = telehub / 1 = infohub
535 );
507 mapitems.Add(mapitem); 536 mapitems.Add(mapitem);
508 537
509 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); 538 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
@@ -523,7 +552,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
523 /// </summary> 552 /// </summary>
524 public void process() 553 public void process()
525 { 554 {
526 const int MAX_ASYNC_REQUESTS = 20; 555 //const int MAX_ASYNC_REQUESTS = 20;
527 try 556 try
528 { 557 {
529 while (true) 558 while (true)
@@ -568,13 +597,44 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
568 Watchdog.RemoveThread(); 597 Watchdog.RemoveThread();
569 } 598 }
570 599
600 const int MAX_ASYNC_REQUESTS = 20;
601
571 /// <summary> 602 /// <summary>
572 /// Enqueues the map item request into the processing thread 603 /// Enqueues the map item request into the services throttle processing thread
573 /// </summary> 604 /// </summary>
574 /// <param name="state"></param> 605 /// <param name="state"></param>
575 public void EnqueueMapItemRequest(MapRequestState state) 606 public void EnqueueMapItemRequest(MapRequestState st)
576 { 607 {
577 requests.Enqueue(state); 608
609 m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate
610 {
611 if (st.agentID != UUID.Zero)
612 {
613 bool dorequest = true;
614 lock (m_rootAgents)
615 {
616 if (!m_rootAgents.Contains(st.agentID))
617 dorequest = false;
618 }
619
620 if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle))
621 {
622 if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
623 {
624 // AH!!! Recursive !
625 // Put this request back in the queue and return
626 EnqueueMapItemRequest(st);
627 return;
628 }
629
630 RequestMapItemsDelegate d = RequestMapItemsAsync;
631 d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null);
632 //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
633 //RequestMapItemsCompleted(response);
634 Interlocked.Increment(ref nAsyncRequests);
635 }
636 }
637 });
578 } 638 }
579 639
580 /// <summary> 640 /// <summary>
@@ -622,19 +682,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
622 { 682 {
623 OSDMap mapitem = (OSDMap)itemarray[i]; 683 OSDMap mapitem = (OSDMap)itemarray[i];
624 mapItemReply mi = new mapItemReply(); 684 mapItemReply mi = new mapItemReply();
625 mi.x = (uint)mapitem["X"].AsInteger(); 685 mi.FromOSD(mapitem);
626 mi.y = (uint)mapitem["Y"].AsInteger();
627 mi.id = mapitem["ID"].AsUUID();
628 mi.Extra = mapitem["Extra"].AsInteger();
629 mi.Extra2 = mapitem["Extra2"].AsInteger();
630 mi.name = mapitem["Name"].AsString();
631 returnitems.Add(mi); 686 returnitems.Add(mi);
632 } 687 }
633 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); 688 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
634 } 689 }
635 690
636 // Service 7 (MAP_ITEM_LAND_FOR_SALE) 691 // Service 7 (MAP_ITEM_LAND_FOR_SALE)
637 uint itemtype = 7; 692 uint itemtype = (uint)GridItemType.LandForSale;
638 693
639 if (response.ContainsKey(itemtype.ToString())) 694 if (response.ContainsKey(itemtype.ToString()))
640 { 695 {
@@ -644,19 +699,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
644 { 699 {
645 OSDMap mapitem = (OSDMap)itemarray[i]; 700 OSDMap mapitem = (OSDMap)itemarray[i];
646 mapItemReply mi = new mapItemReply(); 701 mapItemReply mi = new mapItemReply();
647 mi.x = (uint)mapitem["X"].AsInteger(); 702 mi.FromOSD(mapitem);
648 mi.y = (uint)mapitem["Y"].AsInteger();
649 mi.id = mapitem["ID"].AsUUID();
650 mi.Extra = mapitem["Extra"].AsInteger();
651 mi.Extra2 = mapitem["Extra2"].AsInteger();
652 mi.name = mapitem["Name"].AsString();
653 returnitems.Add(mi); 703 returnitems.Add(mi);
654 } 704 }
655 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); 705 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
656 } 706 }
657 707
658 // Service 1 (MAP_ITEM_TELEHUB) 708 // Service 1 (MAP_ITEM_TELEHUB)
659 itemtype = 1; 709 itemtype = (uint)GridItemType.Telehub;
660 710
661 if (response.ContainsKey(itemtype.ToString())) 711 if (response.ContainsKey(itemtype.ToString()))
662 { 712 {
@@ -666,12 +716,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
666 { 716 {
667 OSDMap mapitem = (OSDMap)itemarray[i]; 717 OSDMap mapitem = (OSDMap)itemarray[i];
668 mapItemReply mi = new mapItemReply(); 718 mapItemReply mi = new mapItemReply();
669 mi.x = (uint)mapitem["X"].AsInteger(); 719 mi.FromOSD(mapitem);
670 mi.y = (uint)mapitem["Y"].AsInteger();
671 mi.id = mapitem["ID"].AsUUID();
672 mi.Extra = mapitem["Extra"].AsInteger();
673 mi.Extra2 = mapitem["Extra2"].AsInteger();
674 mi.name = mapitem["Name"].AsString();
675 returnitems.Add(mi); 720 returnitems.Add(mi);
676 } 721 }
677 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); 722 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
@@ -754,7 +799,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
754 if (httpserver.Length == 0) 799 if (httpserver.Length == 0)
755 { 800 {
756 uint x = 0, y = 0; 801 uint x = 0, y = 0;
757 Utils.LongToUInts(regionhandle, out x, out y); 802 Util.RegionHandleToWorldLoc(regionhandle, out x, out y);
758 GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); 803 GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
759 804
760 if (mreg != null) 805 if (mreg != null)
@@ -861,24 +906,26 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
861 finally 906 finally
862 { 907 {
863 if (os != null) 908 if (os != null)
864 os.Close(); 909 os.Dispose();
865 } 910 }
866 911
867 string response_mapItems_reply = null; 912 string response_mapItems_reply = null;
868 { // get the response 913 {
869 StreamReader sr = null;
870 try 914 try
871 { 915 {
872 WebResponse webResponse = mapitemsrequest.GetResponse(); 916 using (WebResponse webResponse = mapitemsrequest.GetResponse())
873 if (webResponse != null)
874 {
875 sr = new StreamReader(webResponse.GetResponseStream());
876 response_mapItems_reply = sr.ReadToEnd().Trim();
877 }
878 else
879 { 917 {
880 return new OSDMap(); 918 if (webResponse != null)
881 } 919 {
920 using (Stream s = webResponse.GetResponseStream())
921 using (StreamReader sr = new StreamReader(s))
922 response_mapItems_reply = sr.ReadToEnd().Trim();
923 }
924 else
925 {
926 return new OSDMap();
927 }
928 }
882 } 929 }
883 catch (WebException) 930 catch (WebException)
884 { 931 {
@@ -905,11 +952,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
905 952
906 return responseMap; 953 return responseMap;
907 } 954 }
908 finally
909 {
910 if (sr != null)
911 sr.Close();
912 }
913 955
914 OSD rezResponse = null; 956 OSD rezResponse = null;
915 try 957 try
@@ -923,6 +965,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
923 { 965 {
924 m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); 966 m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message);
925 responseMap["connect"] = OSD.FromBoolean(false); 967 responseMap["connect"] = OSD.FromBoolean(false);
968
926 lock (m_blacklistedregions) 969 lock (m_blacklistedregions)
927 { 970 {
928 if (!m_blacklistedregions.ContainsKey(regionhandle)) 971 if (!m_blacklistedregions.ContainsKey(regionhandle))
@@ -955,7 +998,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
955 /// <param name="maxY"></param> 998 /// <param name="maxY"></param>
956 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) 999 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
957 { 1000 {
958 //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
959 if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible 1001 if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
960 { 1002 {
961 List<MapBlockData> response = new List<MapBlockData>(); 1003 List<MapBlockData> response = new List<MapBlockData>();
@@ -964,22 +1006,24 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
964 // on an unloaded square. 1006 // on an unloaded square.
965 // But make sure: Look whether the one we requested is in there 1007 // But make sure: Look whether the one we requested is in there
966 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 1008 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
967 minX * (int)Constants.RegionSize, 1009 (int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX),
968 maxX * (int)Constants.RegionSize, 1010 (int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) );
969 minY * (int)Constants.RegionSize,
970 maxY * (int)Constants.RegionSize);
971 1011
1012 m_log.DebugFormat("[WORLD MAP MODULE] RequestMapBlocks min=<{0},{1}>, max=<{2},{3}>, flag={4}, cntFound={5}",
1013 minX, minY, maxX, maxY, flag.ToString("X"), regions.Count);
972 if (regions != null) 1014 if (regions != null)
973 { 1015 {
974 foreach (GridRegion r in regions) 1016 foreach (GridRegion r in regions)
975 { 1017 {
976 if ((r.RegionLocX == minX * (int)Constants.RegionSize) && 1018 if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX)
977 (r.RegionLocY == minY * (int)Constants.RegionSize)) 1019 && r.RegionLocY == Util.RegionToWorldLoc((uint)minY) )
978 { 1020 {
979 // found it => add it to response 1021 // found it => add it to response
980 MapBlockData block = new MapBlockData(); 1022 // Version 2 viewers can handle the larger regions
981 MapBlockFromGridRegion(block, r, flag); 1023 if ((flag & 2) == 2)
982 response.Add(block); 1024 response.AddRange(Map2BlockFromGridRegion(r, flag));
1025 else
1026 response.Add(MapBlockFromGridRegion(r, flag));
983 break; 1027 break;
984 } 1028 }
985 } 1029 }
@@ -991,7 +1035,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
991 MapBlockData block = new MapBlockData(); 1035 MapBlockData block = new MapBlockData();
992 block.X = (ushort)minX; 1036 block.X = (ushort)minX;
993 block.Y = (ushort)minY; 1037 block.Y = (ushort)minY;
994 block.Access = 254; // means 'simulator is offline' 1038 block.Access = (byte)SimAccess.Down; // means 'simulator is offline'
1039 // block.Access = (byte)SimAccess.NonExistent;
995 response.Add(block); 1040 response.Add(block);
996 } 1041 }
997 // The lower 16 bits are an unsigned int16 1042 // The lower 16 bits are an unsigned int16
@@ -1008,39 +1053,94 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1008 { 1053 {
1009 List<MapBlockData> mapBlocks = new List<MapBlockData>(); 1054 List<MapBlockData> mapBlocks = new List<MapBlockData>();
1010 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 1055 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1011 (minX - 4) * (int)Constants.RegionSize, 1056 (int)Util.RegionToWorldLoc((uint)(minX - 4)), (int)Util.RegionToWorldLoc((uint)(maxX + 4)),
1012 (maxX + 4) * (int)Constants.RegionSize, 1057 (int)Util.RegionToWorldLoc((uint)(minY - 4)), (int)Util.RegionToWorldLoc((uint)(maxY + 4)) );
1013 (minY - 4) * (int)Constants.RegionSize, 1058 //m_log.DebugFormat("{0} GetAndSendBlocks. min=<{1},{2}>, max=<{3},{4}>, cntFound={5}",
1014 (maxY + 4) * (int)Constants.RegionSize); 1059 // LogHeader, minX, minY, maxX, maxY, regions.Count);
1015 foreach (GridRegion r in regions) 1060 foreach (GridRegion r in regions)
1016 { 1061 {
1017 MapBlockData block = new MapBlockData(); 1062 // Version 2 viewers can handle the larger regions
1018 MapBlockFromGridRegion(block, r, flag); 1063 if ((flag & 2) == 2)
1019 mapBlocks.Add(block); 1064 mapBlocks.AddRange(Map2BlockFromGridRegion(r, flag));
1065 else
1066 mapBlocks.Add(MapBlockFromGridRegion(r, flag));
1020 } 1067 }
1021 remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); 1068 remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
1022 1069
1023 return mapBlocks; 1070 return mapBlocks;
1024 } 1071 }
1025 1072
1026 protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) 1073 // Fill a passed MapBlockData from a GridRegion
1074 public MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag)
1027 { 1075 {
1076 MapBlockData block = new MapBlockData();
1077
1028 block.Access = r.Access; 1078 block.Access = r.Access;
1029 switch (flag & 0xffff) 1079 switch (flag & 0xffff)
1030 { 1080 {
1031 case 0: 1081 case 0:
1032 block.MapImageId = r.TerrainImage; 1082 block.MapImageId = r.TerrainImage;
1033 break; 1083 break;
1034 case 2: 1084 case 2:
1035 block.MapImageId = r.ParcelImage; 1085 block.MapImageId = r.ParcelImage;
1036 break; 1086 break;
1037 default: 1087 default:
1038 block.MapImageId = UUID.Zero; 1088 block.MapImageId = UUID.Zero;
1039 break; 1089 break;
1040 } 1090 }
1041 block.Name = r.RegionName; 1091 block.Name = r.RegionName;
1042 block.X = (ushort)(r.RegionLocX / Constants.RegionSize); 1092 block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX);
1043 block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); 1093 block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY);
1094 block.SizeX = (ushort) r.RegionSizeX;
1095 block.SizeY = (ushort) r.RegionSizeY;
1096
1097 return block;
1098 }
1099
1100 public List<MapBlockData> Map2BlockFromGridRegion(GridRegion r, uint flag)
1101 {
1102 List<MapBlockData> blocks = new List<MapBlockData>();
1103 MapBlockData block = new MapBlockData();
1104 if (r == null)
1105 {
1106 block.Access = (byte)SimAccess.Down;
1107 block.MapImageId = UUID.Zero;
1108 blocks.Add(block);
1109 }
1110 else
1111 {
1112 block.Access = r.Access;
1113 switch (flag & 0xffff)
1114 {
1115 case 0:
1116 block.MapImageId = r.TerrainImage;
1117 break;
1118 case 2:
1119 block.MapImageId = r.ParcelImage;
1120 break;
1121 default:
1122 block.MapImageId = UUID.Zero;
1123 break;
1124 }
1125 block.Name = r.RegionName;
1126 block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
1127 block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
1128 block.SizeX = (ushort)r.RegionSizeX;
1129 block.SizeY = (ushort)r.RegionSizeY;
1130 blocks.Add(block);
1131 }
1132 return blocks;
1133 }
1134
1135
1136 public Hashtable OnHTTPThrottled(Hashtable keysvals)
1137 {
1138 Hashtable reply = new Hashtable();
1139 int statuscode = 500;
1140 reply["str_response_string"] = "";
1141 reply["int_response_code"] = statuscode;
1142 reply["content_type"] = "text/plain";
1143 return reply;
1044 } 1144 }
1045 1145
1046 public Hashtable OnHTTPGetMapImage(Hashtable keysvals) 1146 public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
@@ -1052,7 +1152,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1052 1152
1053 if (myMapImageJPEG.Length == 0) 1153 if (myMapImageJPEG.Length == 0)
1054 { 1154 {
1055 MemoryStream imgstream = new MemoryStream(); 1155 MemoryStream imgstream = null;
1056 Bitmap mapTexture = new Bitmap(1,1); 1156 Bitmap mapTexture = new Bitmap(1,1);
1057 ManagedImage managedImage; 1157 ManagedImage managedImage;
1058 Image image = (Image)mapTexture; 1158 Image image = (Image)mapTexture;
@@ -1099,10 +1199,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1099 image.Dispose(); 1199 image.Dispose();
1100 1200
1101 if (imgstream != null) 1201 if (imgstream != null)
1102 {
1103 imgstream.Close();
1104 imgstream.Dispose(); 1202 imgstream.Dispose();
1105 }
1106 } 1203 }
1107 } 1204 }
1108 else 1205 else
@@ -1161,17 +1258,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1161 1258
1162 List<MapBlockData> mapBlocks = new List<MapBlockData>(); 1259 List<MapBlockData> mapBlocks = new List<MapBlockData>();
1163 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 1260 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1164 (int)(m_scene.RegionInfo.RegionLocX - 9) * (int)Constants.RegionSize, 1261 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 9),
1165 (int)(m_scene.RegionInfo.RegionLocX + 9) * (int)Constants.RegionSize, 1262 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 9),
1166 (int)(m_scene.RegionInfo.RegionLocY - 9) * (int)Constants.RegionSize, 1263 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 9),
1167 (int)(m_scene.RegionInfo.RegionLocY + 9) * (int)Constants.RegionSize); 1264 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 9));
1168 List<AssetBase> textures = new List<AssetBase>(); 1265 List<AssetBase> textures = new List<AssetBase>();
1169 List<Image> bitImages = new List<Image>(); 1266 List<Image> bitImages = new List<Image>();
1170 1267
1171 foreach (GridRegion r in regions) 1268 foreach (GridRegion r in regions)
1172 { 1269 {
1173 MapBlockData mapBlock = new MapBlockData(); 1270 MapBlockData mapBlock = MapBlockFromGridRegion(r, 0);
1174 MapBlockFromGridRegion(mapBlock, r, 0);
1175 AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); 1271 AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
1176 1272
1177 if (texAsset != null) 1273 if (texAsset != null)
@@ -1217,12 +1313,34 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1217 m_scene.RegionInfo.RegionName, exportPath); 1313 m_scene.RegionInfo.RegionName, exportPath);
1218 } 1314 }
1219 1315
1316 public void HandleGenerateMapConsoleCommand(string module, string[] cmdparams)
1317 {
1318 Scene consoleScene = m_scene.ConsoleScene();
1319
1320 if (consoleScene != null && consoleScene != m_scene)
1321 return;
1322
1323 if (m_mapImageGenerator == null)
1324 {
1325 Console.WriteLine("No map image generator available for {0}", m_scene.Name);
1326 return;
1327 }
1328
1329 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
1330 {
1331 GenerateMaptile(mapbmp);
1332 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
1333 }
1334 }
1335
1220 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) 1336 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
1221 { 1337 {
1222 uint xstart = 0; 1338 uint xstart = 0;
1223 uint ystart = 0; 1339 uint ystart = 0;
1224 1340
1225 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); 1341 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
1342 // m_log.DebugFormat("{0} HandleRemoteMapItemRequest. loc=<{1},{2}>",
1343 // LogHeader, Util.WorldToRegionLoc(xstart), Util.WorldToRegionLoc(ystart));
1226 1344
1227 // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots) 1345 // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots)
1228 1346
@@ -1337,20 +1455,35 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1337 1455
1338 public void GenerateMaptile() 1456 public void GenerateMaptile()
1339 { 1457 {
1340 // Cannot create a map for a nonexistant heightmap 1458 // Cannot create a map for a nonexistent heightmap
1341 if (m_scene.Heightmap == null) 1459 if (m_scene.Heightmap == null)
1342 return; 1460 return;
1343 1461
1344 //create a texture asset of the terrain 1462 m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name);
1345 IMapImageGenerator terrain = m_scene.RequestModuleInterface<IMapImageGenerator>(); 1463
1346 if (terrain == null) 1464 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
1347 return; 1465 {
1466 // V1 (This Module)
1467 GenerateMaptile(mapbmp);
1468
1469 // v2/3 (MapImageServiceModule)
1470 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
1471 }
1472 }
1348 1473
1349 m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName); 1474 private void GenerateMaptile(Bitmap mapbmp)
1475 {
1476 byte[] data;
1350 1477
1351 byte[] data = terrain.WriteJpeg2000Image(); 1478 try
1352 if (data == null) 1479 {
1480 data = OpenJPEG.EncodeFromImage(mapbmp, true);
1481 }
1482 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
1483 {
1484 m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e);
1353 return; 1485 return;
1486 }
1354 1487
1355 byte[] overlay = GenerateOverlay(); 1488 byte[] overlay = GenerateOverlay();
1356 1489
@@ -1448,62 +1581,80 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1448 1581
1449 private Byte[] GenerateOverlay() 1582 private Byte[] GenerateOverlay()
1450 { 1583 {
1451 Bitmap overlay = new Bitmap(256, 256); 1584 // These need to be ints for bitmap generation
1585 int regionSizeX = (int)m_scene.RegionInfo.RegionSizeX;
1586 int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY;
1452 1587
1453 bool[,] saleBitmap = new bool[64, 64]; 1588 int landTileSize = LandManagementModule.LandUnit;
1454 for (int x = 0 ; x < 64 ; x++) 1589 int regionLandTilesX = regionSizeX / landTileSize;
1455 { 1590 int regionLandTilesY = regionSizeY / landTileSize;
1456 for (int y = 0 ; y < 64 ; y++)
1457 saleBitmap[x, y] = false;
1458 }
1459 1591
1460 bool landForSale = false; 1592 using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY))
1593 {
1594 bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY];
1595 for (int x = 0; x < regionLandTilesX; x++)
1596 {
1597 for (int y = 0; y < regionLandTilesY; y++)
1598 saleBitmap[x, y] = false;
1599 }
1461 1600
1462 List<ILandObject> parcels = m_scene.LandChannel.AllParcels(); 1601 bool landForSale = false;
1463 1602
1464 Color background = Color.FromArgb(0, 0, 0, 0); 1603 List<ILandObject> parcels = m_scene.LandChannel.AllParcels();
1465 SolidBrush transparent = new SolidBrush(background);
1466 Graphics g = Graphics.FromImage(overlay);
1467 g.FillRectangle(transparent, 0, 0, 256, 256);
1468 1604
1469 SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)); 1605 Color background = Color.FromArgb(0, 0, 0, 0);
1470 1606
1471 foreach (ILandObject land in parcels) 1607 using (Graphics g = Graphics.FromImage(overlay))
1472 {
1473 // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
1474 if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
1475 { 1608 {
1476 landForSale = true; 1609 using (SolidBrush transparent = new SolidBrush(background))
1610 g.FillRectangle(transparent, 0, 0, regionSizeX, regionSizeY);
1477 1611
1478 saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap()); 1612 foreach (ILandObject land in parcels)
1479 } 1613 {
1480 } 1614 // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
1615 if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
1616 {
1617 landForSale = true;
1481 1618
1482 if (!landForSale) 1619 saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap());
1483 { 1620 }
1484 m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName); 1621 }
1485 return null; 1622
1486 } 1623 if (!landForSale)
1624 {
1625 m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
1626 return null;
1627 }
1487 1628
1488 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName); 1629 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
1489 1630
1490 for (int x = 0 ; x < 64 ; x++) 1631 using (SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)))
1491 { 1632 {
1492 for (int y = 0 ; y < 64 ; y++) 1633 for (int x = 0 ; x < regionLandTilesX ; x++)
1634 {
1635 for (int y = 0 ; y < regionLandTilesY ; y++)
1636 {
1637 if (saleBitmap[x, y])
1638 g.FillRectangle(
1639 yellow, x * landTileSize,
1640 regionSizeX - landTileSize - (y * landTileSize),
1641 landTileSize,
1642 landTileSize);
1643 }
1644 }
1645 }
1646 }
1647
1648 try
1493 { 1649 {
1494 if (saleBitmap[x, y]) 1650 return OpenJPEG.EncodeFromImage(overlay, true);
1495 g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4); 1651 }
1652 catch (Exception e)
1653 {
1654 m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
1496 } 1655 }
1497 } 1656 }
1498 1657
1499 try
1500 {
1501 return OpenJPEG.EncodeFromImage(overlay, true);
1502 }
1503 catch (Exception e)
1504 {
1505 m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
1506 }
1507 return null; 1658 return null;
1508 } 1659 }
1509 } 1660 }