aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/World')
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveConstants.cs128
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs460
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs161
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs333
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs95
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs143
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs184
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs138
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/RegionSettingsSerializer.cs258
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs195
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs202
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs188
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs1012
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs127
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandChannel.cs188
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs1347
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs930
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs1498
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/IFileSerialiser.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs125
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/SerialiseTerrain.cs53
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs226
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs97
-rw-r--r--OpenSim/Region/CoreModules/World/Sun/SunModule.cs434
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/DefaultEffects/ChannelDigger.cs107
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs125
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs56
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs76
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs61
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs195
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs112
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs250
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs61
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs170
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs61
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs142
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs70
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs54
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs58
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs54
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs67
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs114
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainEffect.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs37
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs42
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainModule.cs61
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs318
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs101
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs84
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs67
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs223
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs80
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs80
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs100
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs211
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainException.cs46
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs1001
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs118
-rw-r--r--OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs118
-rw-r--r--OpenSim/Region/CoreModules/World/Wind/WindModule.cs207
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs39
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs586
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs172
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs249
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs411
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs905
67 files changed, 15719 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveConstants.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveConstants.cs
new file mode 100644
index 0000000..179d1a2
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveConstants.cs
@@ -0,0 +1,128 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using OpenMetaverse;
30
31namespace OpenSim.Region.CoreModules.World.Archiver
32{
33 /// <summary>
34 /// Constants for the archiving module
35 /// </summary>
36 public class ArchiveConstants
37 {
38 /// <summary>
39 /// The location of the archive control file
40 /// </summary>
41 public static readonly string CONTROL_FILE_PATH = "archive.xml";
42
43 /// <summary>
44 /// Path for the assets held in an archive
45 /// </summary>
46 public static readonly string ASSETS_PATH = "assets/";
47
48 /// <summary>
49 /// Path for the assets metadata file
50 /// </summary>
51 //public static readonly string ASSETS_METADATA_PATH = "assets.xml";
52
53 /// <summary>
54 /// Path for the prims file
55 /// </summary>
56 public static readonly string OBJECTS_PATH = "objects/";
57
58 /// <summary>
59 /// Path for terrains. Technically these may be assets, but I think it's quite nice to split them out.
60 /// </summary>
61 public static readonly string TERRAINS_PATH = "terrains/";
62
63 /// <summary>
64 /// Path for region settings.
65 /// </summary>
66 public static readonly string SETTINGS_PATH = "settings/";
67
68 /// <summary>
69 /// The character the separates the uuid from extension information in an archived asset filename
70 /// </summary>
71 public static readonly string ASSET_EXTENSION_SEPARATOR = "_";
72
73 /// <summary>
74 /// Extensions used for asset types in the archive
75 /// </summary>
76 public static readonly IDictionary<sbyte, string> ASSET_TYPE_TO_EXTENSION = new Dictionary<sbyte, string>();
77 public static readonly IDictionary<string, sbyte> EXTENSION_TO_ASSET_TYPE = new Dictionary<string, sbyte>();
78
79 static ArchiveConstants()
80 {
81 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Animation] = ASSET_EXTENSION_SEPARATOR + "animation.bvh";
82 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Bodypart] = ASSET_EXTENSION_SEPARATOR + "bodypart.txt";
83 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.CallingCard] = ASSET_EXTENSION_SEPARATOR + "callingcard.txt";
84 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Clothing] = ASSET_EXTENSION_SEPARATOR + "clothing.txt";
85 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Folder] = ASSET_EXTENSION_SEPARATOR + "folder.txt"; // Not sure if we'll ever see this
86 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Gesture] = ASSET_EXTENSION_SEPARATOR + "gesture.txt";
87 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg";
88 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga";
89 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt";
90 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this
91 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso";
92 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl";
93 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt";
94 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml";
95 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this
96 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this
97 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this
98 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg";
99 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav";
100 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2";
101 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga";
102 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this
103
104 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation;
105 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart;
106 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "callingcard.txt"] = (sbyte)AssetType.CallingCard;
107 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "clothing.txt"] = (sbyte)AssetType.Clothing;
108 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "folder.txt"] = (sbyte)AssetType.Folder;
109 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "gesture.txt"] = (sbyte)AssetType.Gesture;
110 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = (sbyte)AssetType.ImageJPEG;
111 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = (sbyte)AssetType.ImageTGA;
112 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = (sbyte)AssetType.Landmark;
113 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = (sbyte)AssetType.LostAndFoundFolder;
114 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = (sbyte)AssetType.LSLBytecode;
115 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = (sbyte)AssetType.LSLText;
116 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = (sbyte)AssetType.Notecard;
117 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = (sbyte)AssetType.Object;
118 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = (sbyte)AssetType.RootFolder;
119 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = (sbyte)AssetType.Simstate;
120 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = (sbyte)AssetType.SnapshotFolder;
121 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = (sbyte)AssetType.Sound;
122 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = (sbyte)AssetType.SoundWAV;
123 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture;
124 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA;
125 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
126 }
127 }
128}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
new file mode 100644
index 0000000..3218abc
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -0,0 +1,460 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.IO.Compression;
32using System.Reflection;
33using System.Xml;
34using System.Net;
35using OpenMetaverse;
36using log4net;
37using OpenSim.Framework;
38using OpenSim.Framework.Communications.Cache;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.CoreModules.World.Terrain;
42
43namespace OpenSim.Region.CoreModules.World.Archiver
44{
45 /// <summary>
46 /// Handles an individual archive read request
47 /// </summary>
48 public class ArchiveReadRequest
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private static System.Text.ASCIIEncoding m_asciiEncoding = new System.Text.ASCIIEncoding();
53
54 private Scene m_scene;
55 private Stream m_loadStream;
56 private string m_errorMessage;
57
58 /// <summary>
59 /// Used to cache lookups for valid uuids.
60 /// </summary>
61 private IDictionary<UUID, bool> m_validUserUuids = new Dictionary<UUID, bool>();
62
63 public ArchiveReadRequest(Scene scene, string loadPath)
64 {
65 m_scene = scene;
66 m_loadStream = new GZipStream(GetStream(loadPath), CompressionMode.Decompress);
67 m_errorMessage = String.Empty;
68 }
69
70 public ArchiveReadRequest(Scene scene, Stream loadStream)
71 {
72 m_scene = scene;
73 m_loadStream = loadStream;
74 }
75
76 /// <summary>
77 /// Dearchive the region embodied in this request.
78 /// </summary>
79 public void DearchiveRegion()
80 {
81 // The same code can handle dearchiving 0.1 and 0.2 OpenSim Archive versions
82 DearchiveRegion0DotStar();
83 }
84
85 private void DearchiveRegion0DotStar()
86 {
87 int successfulAssetRestores = 0;
88 int failedAssetRestores = 0;
89 List<string> serialisedSceneObjects = new List<string>();
90
91 try
92 {
93 TarArchiveReader archive = new TarArchiveReader(m_loadStream);
94
95 //AssetsDearchiver dearchiver = new AssetsDearchiver(m_scene.AssetCache);
96
97 string filePath = "ERROR";
98
99 byte[] data;
100 TarArchiveReader.TarEntryType entryType;
101
102 while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
103 {
104 //m_log.DebugFormat(
105 // "[ARCHIVER]: Successfully read {0} ({1} bytes)}", filePath, data.Length);
106 if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
107 {
108 m_log.WarnFormat("[ARCHIVER]: Ignoring directory entry {0}",
109 filePath);
110 }
111 else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
112 {
113 serialisedSceneObjects.Add(m_asciiEncoding.GetString(data));
114 }
115// else if (filePath.Equals(ArchiveConstants.ASSETS_METADATA_PATH))
116// {
117// string xml = m_asciiEncoding.GetString(data);
118// dearchiver.AddAssetMetadata(xml);
119// }
120 else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
121 {
122 if (LoadAsset(filePath, data))
123 successfulAssetRestores++;
124 else
125 failedAssetRestores++;
126 }
127 else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
128 {
129 LoadTerrain(filePath, data);
130 }
131 else if (filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
132 {
133 LoadRegionSettings(filePath, data);
134 }
135 }
136
137 //m_log.Debug("[ARCHIVER]: Reached end of archive");
138
139 archive.Close();
140 }
141 catch (Exception e)
142 {
143 m_log.ErrorFormat(
144 "[ARCHIVER]: Error loading oar file. Exception was: {0}", e);
145 m_errorMessage += e.ToString();
146 m_scene.EventManager.TriggerOarFileLoaded(m_errorMessage);
147 return;
148 }
149
150 m_log.InfoFormat("[ARCHIVER]: Restored {0} assets", successfulAssetRestores);
151
152 if (failedAssetRestores > 0)
153 {
154 m_log.ErrorFormat("[ARCHIVER]: Failed to load {0} assets", failedAssetRestores);
155 m_errorMessage += String.Format("Failed to load {0} assets", failedAssetRestores);
156 }
157
158 m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
159 m_scene.DeleteAllSceneObjects();
160
161 // Reload serialized prims
162 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
163
164 IRegionSerialiserModule serialiser = m_scene.RequestModuleInterface<IRegionSerialiserModule>();
165 ICollection<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
166
167 foreach (string serialisedSceneObject in serialisedSceneObjects)
168 {
169 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
170
171 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
172 // on the same region server and multiple examples a single object archive to be imported
173 // to the same scene (when this is possible).
174 sceneObject.ResetIDs();
175
176 // Try to retain the original creator/owner/lastowner if their uuid is present on this grid
177 // otherwise, use the master avatar uuid instead
178 UUID masterAvatarId = m_scene.RegionInfo.MasterAvatarAssignedUUID;
179
180 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero)
181 masterAvatarId = m_scene.RegionInfo.EstateSettings.EstateOwner;
182
183 foreach (SceneObjectPart part in sceneObject.Children.Values)
184 {
185 if (!resolveUserUuid(part.CreatorID))
186 part.CreatorID = masterAvatarId;
187
188 if (!resolveUserUuid(part.OwnerID))
189 part.OwnerID = masterAvatarId;
190
191 if (!resolveUserUuid(part.LastOwnerID))
192 part.LastOwnerID = masterAvatarId;
193
194 // And zap any troublesome sit target information
195 part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
196 part.SitTargetPosition = new Vector3(0, 0, 0);
197
198 // Fix ownership/creator of inventory items
199 // Not doing so results in inventory items
200 // being no copy/no mod for everyone
201 TaskInventoryDictionary inv = part.TaskInventory;
202 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
203 {
204 if (!resolveUserUuid(kvp.Value.OwnerID))
205 {
206 kvp.Value.OwnerID = masterAvatarId;
207 }
208 if (!resolveUserUuid(kvp.Value.CreatorID))
209 {
210 kvp.Value.CreatorID = masterAvatarId;
211 }
212 }
213 }
214
215 if (m_scene.AddRestoredSceneObject(sceneObject, true, false))
216 {
217 sceneObjects.Add(sceneObject);
218 }
219 }
220
221 m_log.InfoFormat("[ARCHIVER]: Restored {0} scene objects to the scene", sceneObjects.Count);
222
223 int ignoredObjects = serialisedSceneObjects.Count - sceneObjects.Count;
224
225 if (ignoredObjects > 0)
226 m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene", ignoredObjects);
227
228 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive");
229
230 m_log.Debug("[ARCHIVER]: Starting scripts");
231
232 foreach (SceneObjectGroup sceneObject in sceneObjects)
233 {
234 sceneObject.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 0);
235 }
236
237 m_scene.EventManager.TriggerOarFileLoaded(m_errorMessage);
238 }
239
240 /// <summary>
241 /// Look up the given user id to check whether it's one that is valid for this grid.
242 /// </summary>
243 /// <param name="uuid"></param>
244 /// <returns></returns>
245 private bool resolveUserUuid(UUID uuid)
246 {
247 if (!m_validUserUuids.ContainsKey(uuid))
248 {
249 CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(uuid);
250 if (profile != null && profile.UserProfile != null)
251 m_validUserUuids.Add(uuid, true);
252 else
253 m_validUserUuids.Add(uuid, false);
254 }
255
256 if (m_validUserUuids[uuid])
257 return true;
258 else
259 return false;
260 }
261
262 /// <summary>
263 /// Load an asset
264 /// </summary>
265 /// <param name="assetFilename"></param>
266 /// <param name="data"></param>
267 /// <returns>true if asset was successfully loaded, false otherwise</returns>
268 private bool LoadAsset(string assetPath, byte[] data)
269 {
270 // Right now we're nastily obtaining the UUID from the filename
271 string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
272 int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR);
273
274 if (i == -1)
275 {
276 m_log.ErrorFormat(
277 "[ARCHIVER]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping",
278 assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR);
279
280 return false;
281 }
282
283 string extension = filename.Substring(i);
284 string uuid = filename.Remove(filename.Length - extension.Length);
285
286 if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension))
287 {
288 sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension];
289
290 //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType);
291
292 AssetBase asset = new AssetBase(new UUID(uuid), String.Empty);
293 asset.Metadata.Type = assetType;
294 asset.Data = data;
295
296 m_scene.AssetCache.AddAsset(asset);
297
298 /**
299 * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so
300 * it might be best done when dearchive takes place on a separate thread
301 if (asset.Type=AssetType.Texture)
302 {
303 IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
304 if (cacheLayerDecode != null)
305 cacheLayerDecode.syncdecode(asset.FullID, asset.Data);
306 }
307 */
308
309 return true;
310 }
311 else
312 {
313 m_log.ErrorFormat(
314 "[ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}",
315 assetPath, extension);
316
317 return false;
318 }
319 }
320
321 /// <summary>
322 /// Load region settings data
323 /// </summary>
324 /// <param name="settingsPath"></param>
325 /// <param name="data"></param>
326 /// <returns>
327 /// true if settings were loaded successfully, false otherwise
328 /// </returns>
329 private bool LoadRegionSettings(string settingsPath, byte[] data)
330 {
331 RegionSettings loadedRegionSettings;
332
333 try
334 {
335 loadedRegionSettings = RegionSettingsSerializer.Deserialize(data);
336 }
337 catch (Exception e)
338 {
339 m_log.ErrorFormat(
340 "[ARCHIVER]: Could not parse region settings file {0}. Ignoring. Exception was {1}",
341 settingsPath, e);
342 return false;
343 }
344
345 RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings;
346
347 currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit;
348 currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage;
349 currentRegionSettings.AllowLandJoinDivide = loadedRegionSettings.AllowLandJoinDivide;
350 currentRegionSettings.AllowLandResell = loadedRegionSettings.AllowLandResell;
351 currentRegionSettings.BlockFly = loadedRegionSettings.BlockFly;
352 currentRegionSettings.BlockShowInSearch = loadedRegionSettings.BlockShowInSearch;
353 currentRegionSettings.BlockTerraform = loadedRegionSettings.BlockTerraform;
354 currentRegionSettings.DisableCollisions = loadedRegionSettings.DisableCollisions;
355 currentRegionSettings.DisablePhysics = loadedRegionSettings.DisablePhysics;
356 currentRegionSettings.DisableScripts = loadedRegionSettings.DisableScripts;
357 currentRegionSettings.Elevation1NE = loadedRegionSettings.Elevation1NE;
358 currentRegionSettings.Elevation1NW = loadedRegionSettings.Elevation1NW;
359 currentRegionSettings.Elevation1SE = loadedRegionSettings.Elevation1SE;
360 currentRegionSettings.Elevation1SW = loadedRegionSettings.Elevation1SW;
361 currentRegionSettings.Elevation2NE = loadedRegionSettings.Elevation2NE;
362 currentRegionSettings.Elevation2NW = loadedRegionSettings.Elevation2NW;
363 currentRegionSettings.Elevation2SE = loadedRegionSettings.Elevation2SE;
364 currentRegionSettings.Elevation2SW = loadedRegionSettings.Elevation2SW;
365 currentRegionSettings.FixedSun = loadedRegionSettings.FixedSun;
366 currentRegionSettings.ObjectBonus = loadedRegionSettings.ObjectBonus;
367 currentRegionSettings.RestrictPushing = loadedRegionSettings.RestrictPushing;
368 currentRegionSettings.TerrainLowerLimit = loadedRegionSettings.TerrainLowerLimit;
369 currentRegionSettings.TerrainRaiseLimit = loadedRegionSettings.TerrainRaiseLimit;
370 currentRegionSettings.TerrainTexture1 = loadedRegionSettings.TerrainTexture1;
371 currentRegionSettings.TerrainTexture2 = loadedRegionSettings.TerrainTexture2;
372 currentRegionSettings.TerrainTexture3 = loadedRegionSettings.TerrainTexture3;
373 currentRegionSettings.TerrainTexture4 = loadedRegionSettings.TerrainTexture4;
374 currentRegionSettings.UseEstateSun = loadedRegionSettings.UseEstateSun;
375 currentRegionSettings.WaterHeight = loadedRegionSettings.WaterHeight;
376
377 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
378 estateModule.sendRegionHandshakeToAll();
379
380 return true;
381 }
382
383 /// <summary>
384 /// Load terrain data
385 /// </summary>
386 /// <param name="terrainPath"></param>
387 /// <param name="data"></param>
388 /// <returns>
389 /// true if terrain was resolved successfully, false otherwise.
390 /// </returns>
391 private bool LoadTerrain(string terrainPath, byte[] data)
392 {
393 ITerrainModule terrainModule = m_scene.RequestModuleInterface<ITerrainModule>();
394
395 MemoryStream ms = new MemoryStream(data);
396 terrainModule.LoadFromStream(terrainPath, ms);
397 ms.Close();
398
399 m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath);
400
401 return true;
402 }
403
404 /// <summary>
405 /// Resolve path to a working FileStream
406 /// </summary>
407 private Stream GetStream(string path)
408 {
409 try
410 {
411 if (File.Exists(path))
412 {
413 return new FileStream(path, FileMode.Open);
414 }
415 else
416 {
417 Uri uri = new Uri(path); // throw exception if not valid URI
418 if (uri.Scheme == "file")
419 {
420 return new FileStream(uri.AbsolutePath, FileMode.Open);
421 }
422 else
423 {
424 if (uri.Scheme != "http")
425 throw new Exception(String.Format("Unsupported URI scheme ({0})", path));
426
427 // OK, now we know we have an HTTP URI to work with
428
429 return URIFetch(uri);
430 }
431 }
432 }
433 catch (Exception e)
434 {
435 throw new Exception(String.Format("Unable to create file input stream for {0}: {1}", path, e));
436 }
437 }
438
439 private static Stream URIFetch(Uri uri)
440 {
441 HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
442
443 // request.Credentials = credentials;
444
445 request.ContentLength = 0;
446
447 WebResponse response = request.GetResponse();
448 Stream file = response.GetResponseStream();
449
450 if (response.ContentType != "application/x-oar")
451 throw new Exception(String.Format("{0} does not identify an OAR file", uri.ToString()));
452
453 if (response.ContentLength == 0)
454 throw new Exception(String.Format("{0} returned an empty file", uri.ToString()));
455
456 // return new BufferedStream(file, (int) response.ContentLength);
457 return new BufferedStream(file, 1000000);
458 }
459 }
460}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs
new file mode 100644
index 0000000..d3c2cd1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs
@@ -0,0 +1,161 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33using OpenMetaverse;
34using log4net;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.CoreModules.World.Serialiser;
39using OpenSim.Region.CoreModules.World.Terrain;
40
41namespace OpenSim.Region.CoreModules.World.Archiver
42{
43 /// <summary>
44 /// Method called when all the necessary assets for an archive request have been received.
45 /// </summary>
46 public delegate void AssetsRequestCallback(IDictionary<UUID, AssetBase> assetsFound, ICollection<UUID> assetsNotFoundUuids);
47
48 /// <summary>
49 /// Execute the write of an archive once we have received all the necessary data
50 /// </summary>
51 public class ArchiveWriteRequestExecution
52 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
55 protected ITerrainModule m_terrainModule;
56 protected IRegionSerialiserModule m_serialiser;
57 protected List<SceneObjectGroup> m_sceneObjects;
58 protected Scene m_scene;
59 protected Stream m_saveStream;
60
61 public ArchiveWriteRequestExecution(
62 List<SceneObjectGroup> sceneObjects,
63 ITerrainModule terrainModule,
64 IRegionSerialiserModule serialiser,
65 Scene scene,
66 Stream saveStream)
67 {
68 m_sceneObjects = sceneObjects;
69 m_terrainModule = terrainModule;
70 m_serialiser = serialiser;
71 m_scene = scene;
72 m_saveStream = saveStream;
73 }
74
75 protected internal void ReceivedAllAssets(
76 IDictionary<UUID, AssetBase> assetsFound, ICollection<UUID> assetsNotFoundUuids)
77 {
78 foreach (UUID uuid in assetsNotFoundUuids)
79 {
80 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
81 }
82
83 m_log.InfoFormat(
84 "[ARCHIVER]: Received {0} of {1} assets requested",
85 assetsFound.Count, assetsFound.Count + assetsNotFoundUuids.Count);
86
87 m_log.InfoFormat("[ARCHIVER]: Creating archive file. This may take some time.");
88
89 TarArchiveWriter archive = new TarArchiveWriter();
90
91 // Write out control file
92 archive.AddFile(ArchiveConstants.CONTROL_FILE_PATH, Create0p2ControlFile());
93
94 // Write out region settings
95 string settingsPath
96 = String.Format("{0}{1}.xml", ArchiveConstants.SETTINGS_PATH, m_scene.RegionInfo.RegionName);
97 archive.AddFile(settingsPath, RegionSettingsSerializer.Serialize(m_scene.RegionInfo.RegionSettings));
98
99 // Write out terrain
100 string terrainPath
101 = String.Format("{0}{1}.r32", ArchiveConstants.TERRAINS_PATH, m_scene.RegionInfo.RegionName);
102
103 MemoryStream ms = new MemoryStream();
104 m_terrainModule.SaveToStream(terrainPath, ms);
105 archive.AddFile(terrainPath, ms.ToArray());
106 ms.Close();
107
108 // Write out scene object metadata
109 foreach (SceneObjectGroup sceneObject in m_sceneObjects)
110 {
111 //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
112
113 Vector3 position = sceneObject.AbsolutePosition;
114
115 string serializedObject = m_serialiser.SaveGroupToXml2(sceneObject);
116 string filename
117 = string.Format(
118 "{0}{1}_{2:000}-{3:000}-{4:000}__{5}.xml",
119 ArchiveConstants.OBJECTS_PATH, sceneObject.Name,
120 Math.Round(position.X), Math.Round(position.Y), Math.Round(position.Z),
121 sceneObject.UUID);
122
123 archive.AddFile(filename, serializedObject);
124 }
125
126 // Write out assets
127 AssetsArchiver assetsArchiver = new AssetsArchiver(assetsFound);
128 assetsArchiver.Archive(archive);
129
130 archive.WriteTar(m_saveStream);
131
132 m_log.InfoFormat("[ARCHIVER]: Wrote out OpenSimulator archive for {0}", m_scene.RegionInfo.RegionName);
133
134 m_scene.EventManager.TriggerOarFileSaved(String.Empty);
135 }
136
137 /// <summary>
138 /// Create the control file for a 0.2 version archive
139 /// </summary>
140 /// <returns></returns>
141 public static string Create0p2ControlFile()
142 {
143 StringWriter sw = new StringWriter();
144 XmlTextWriter xtw = new XmlTextWriter(sw);
145 xtw.Formatting = Formatting.Indented;
146 xtw.WriteStartDocument();
147 xtw.WriteStartElement("archive");
148 xtw.WriteAttributeString("major_version", "0");
149 xtw.WriteAttributeString("minor_version", "2");
150 xtw.WriteEndElement();
151
152 xtw.Flush();
153 xtw.Close();
154
155 String s = sw.ToString();
156 sw.Close();
157
158 return s;
159 }
160 }
161}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
new file mode 100644
index 0000000..ee0ec69
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
@@ -0,0 +1,333 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Framework;
29using OpenSim.Framework.Communications.Cache;
30using OpenSim.Region.Framework.Interfaces;
31using OpenSim.Region.Framework.Scenes;
32using OpenSim.Region.CoreModules.World.Serialiser;
33using OpenSim.Region.CoreModules.World.Terrain;
34using System;
35using System.Collections.Generic;
36using System.IO;
37using System.IO.Compression;
38using System.Reflection;
39using System.Text.RegularExpressions;
40using System.Threading;
41using OpenMetaverse;
42using log4net;
43using Nini.Config;
44
45namespace OpenSim.Region.CoreModules.World.Archiver
46{
47 /// <summary>
48 /// Prepare to write out an archive.
49 /// </summary>
50 public class ArchiveWriteRequestPreparation
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 protected Scene m_scene;
55 protected Stream m_saveStream;
56
57 /// <summary>
58 /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate
59 /// asset was found by the asset service.
60 /// </summary>
61 protected AssetBase m_requestedObjectAsset;
62
63 /// <summary>
64 /// Signal whether we are currently waiting for the asset service to deliver an asset.
65 /// </summary>
66 protected bool m_waitingForObjectAsset;
67
68 /// <summary>
69 /// Constructor
70 /// </summary>
71 public ArchiveWriteRequestPreparation(Scene scene, string savePath)
72 {
73 m_scene = scene;
74 m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress);
75 }
76
77 /// <summary>
78 /// Constructor.
79 /// </summary>
80 /// <param name="scene"></param>
81 /// <param name="saveStream">The stream to which to save data.</param>
82 public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream)
83 {
84 m_scene = scene;
85 m_saveStream = saveStream;
86 }
87
88 /// <summary>
89 /// The callback made when we request the asset for an object from the asset service.
90 /// </summary>
91 public void AssetRequestCallback(UUID assetID, AssetBase asset)
92 {
93 lock (this)
94 {
95 m_requestedObjectAsset = asset;
96 m_waitingForObjectAsset = false;
97 Monitor.Pulse(this);
98 }
99 }
100
101 /// <summary>
102 /// Get an asset synchronously, potentially using an asynchronous callback. If the
103 /// asynchronous callback is used, we will wait for it to complete.
104 /// </summary>
105 /// <param name="uuid"></param>
106 /// <returns></returns>
107 protected AssetBase GetAsset(UUID uuid)
108 {
109 m_waitingForObjectAsset = true;
110 m_scene.AssetCache.GetAsset(uuid, AssetRequestCallback, true);
111
112 // The asset cache callback can either
113 //
114 // 1. Complete on the same thread (if the asset is already in the cache) or
115 // 2. Come in via a different thread (if we need to go fetch it).
116 //
117 // The code below handles both these alternatives.
118 lock (this)
119 {
120 if (m_waitingForObjectAsset)
121 {
122 Monitor.Wait(this);
123 m_waitingForObjectAsset = false;
124 }
125 }
126
127 return m_requestedObjectAsset;
128 }
129
130 /// <summary>
131 /// Record the asset uuids embedded within the given script.
132 /// </summary>
133 /// <param name="scriptUuid"></param>
134 /// <param name="assetUuids">Dictionary in which to record the references</param>
135 protected void GetScriptAssetUuids(UUID scriptUuid, IDictionary<UUID, int> assetUuids)
136 {
137 AssetBase scriptAsset = GetAsset(scriptUuid);
138
139 if (null != scriptAsset)
140 {
141 string script = Utils.BytesToString(scriptAsset.Data);
142 //m_log.DebugFormat("[ARCHIVER]: Script {0}", script);
143 MatchCollection uuidMatches = Util.UUIDPattern.Matches(script);
144 //m_log.DebugFormat("[ARCHIVER]: Found {0} matches in script", uuidMatches.Count);
145
146 foreach (Match uuidMatch in uuidMatches)
147 {
148 UUID uuid = new UUID(uuidMatch.Value);
149 //m_log.DebugFormat("[ARCHIVER]: Recording {0} in script", uuid);
150 assetUuids[uuid] = 1;
151 }
152 }
153 }
154
155 /// <summary>
156 /// Record the uuids referenced by the given wearable asset
157 /// </summary>
158 /// <param name="wearableAssetUuid"></param>
159 /// <param name="assetUuids">Dictionary in which to record the references</param>
160 protected void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, int> assetUuids)
161 {
162 AssetBase assetBase = GetAsset(wearableAssetUuid);
163 //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data));
164 AssetWearable wearableAsset = new AssetBodypart(wearableAssetUuid, assetBase.Data);
165 wearableAsset.Decode();
166
167 //m_log.DebugFormat(
168 // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
169
170 foreach (UUID uuid in wearableAsset.Textures.Values)
171 {
172 //m_log.DebugFormat("[ARCHIVER]: Got bodypart uuid {0}", uuid);
173 assetUuids[uuid] = 1;
174 }
175 }
176
177 /// <summary>
178 /// Get all the asset uuids associated with a given object. This includes both those directly associated with
179 /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
180 /// within this object).
181 /// </summary>
182 /// <param name="sceneObject"></param>
183 /// <param name="assetUuids"></param>
184 protected void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, int> assetUuids)
185 {
186 AssetBase objectAsset = GetAsset(sceneObjectUuid);
187
188 if (null != objectAsset)
189 {
190 string xml = Utils.BytesToString(objectAsset.Data);
191 SceneObjectGroup sog = new SceneObjectGroup(xml, true);
192 GetSceneObjectAssetUuids(sog, assetUuids);
193 }
194 }
195
196 /// <summary>
197 /// Get all the asset uuids associated with a given object. This includes both those directly associated with
198 /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
199 /// within this object).
200 /// </summary>
201 /// <param name="sceneObject"></param>
202 /// <param name="assetUuids"></param>
203 protected void GetSceneObjectAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, int> assetUuids)
204 {
205 m_log.DebugFormat(
206 "[ARCHIVER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
207
208 foreach (SceneObjectPart part in sceneObject.GetParts())
209 {
210 //m_log.DebugFormat(
211 // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID);
212
213 try
214 {
215 Primitive.TextureEntry textureEntry = part.Shape.Textures;
216
217 // Get the prim's default texture. This will be used for faces which don't have their own texture
218 assetUuids[textureEntry.DefaultTexture.TextureID] = 1;
219
220 // XXX: Not a great way to iterate through face textures, but there's no
221 // other method available to tell how many faces there actually are
222 //int i = 0;
223 foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
224 {
225 if (texture != null)
226 {
227 //m_log.DebugFormat("[ARCHIVER]: Got face {0}", i++);
228 assetUuids[texture.TextureID] = 1;
229 }
230 }
231
232 // If the prim is a sculpt then preserve this information too
233 if (part.Shape.SculptTexture != UUID.Zero)
234 assetUuids[part.Shape.SculptTexture] = 1;
235
236 // Now analyze this prim's inventory items to preserve all the uuids that they reference
237 foreach (TaskInventoryItem tii in part.TaskInventory.Values)
238 {
239 //m_log.DebugFormat("[ARCHIVER]: Analysing item asset type {0}", tii.Type);
240
241 if (!assetUuids.ContainsKey(tii.AssetID))
242 {
243 assetUuids[tii.AssetID] = 1;
244
245 if ((int)AssetType.Bodypart == tii.Type || ((int)AssetType.Clothing == tii.Type))
246 {
247 GetWearableAssetUuids(tii.AssetID, assetUuids);
248 }
249 else if ((int)AssetType.LSLText == tii.Type)
250 {
251 GetScriptAssetUuids(tii.AssetID, assetUuids);
252 }
253 else if ((int)AssetType.Object == tii.Type)
254 {
255 GetSceneObjectAssetUuids(tii.AssetID, assetUuids);
256 }
257 //else
258 //{
259 //m_log.DebugFormat("[ARCHIVER]: Recording asset {0} in object {1}", tii.AssetID, part.UUID);
260 //}
261 }
262 }
263 }
264 catch (Exception e)
265 {
266 m_log.ErrorFormat("[ARCHIVER]: Failed to get part - {0}", e);
267 m_log.DebugFormat("[ARCHIVER]: Texture entry length for prim was {0} (min is 46)", part.Shape.TextureEntry.Length);
268 }
269 }
270 }
271
272 /// <summary>
273 /// Archive the region requested.
274 /// </summary>
275 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
276 public void ArchiveRegion()
277 {
278 Dictionary<UUID, int> assetUuids = new Dictionary<UUID, int>();
279
280 List<EntityBase> entities = m_scene.GetEntities();
281 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
282
283 // Filter entities so that we only have scene objects.
284 // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
285 // end up having to do this
286 foreach (EntityBase entity in entities)
287 {
288 if (entity is SceneObjectGroup)
289 {
290 SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
291
292 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
293 sceneObjects.Add((SceneObjectGroup)entity);
294 }
295 }
296
297 foreach (SceneObjectGroup sceneObject in sceneObjects)
298 {
299 GetSceneObjectAssetUuids(sceneObject, assetUuids);
300 }
301
302 m_log.DebugFormat(
303 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
304 sceneObjects.Count, assetUuids.Count);
305
306 // Make sure that we also request terrain texture assets
307 RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings;
308
309 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
310 assetUuids[regionSettings.TerrainTexture1] = 1;
311
312 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
313 assetUuids[regionSettings.TerrainTexture2] = 1;
314
315 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
316 assetUuids[regionSettings.TerrainTexture3] = 1;
317
318 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
319 assetUuids[regionSettings.TerrainTexture4] = 1;
320
321 // Asynchronously request all the assets required to perform this archive operation
322 ArchiveWriteRequestExecution awre
323 = new ArchiveWriteRequestExecution(
324 sceneObjects,
325 m_scene.RequestModuleInterface<ITerrainModule>(),
326 m_scene.RequestModuleInterface<IRegionSerialiserModule>(),
327 m_scene,
328 m_saveStream);
329
330 new AssetsRequest(assetUuids.Keys, m_scene.AssetCache, awre.ReceivedAllAssets).Execute();
331 }
332 }
333}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
new file mode 100644
index 0000000..c1f5b18
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
@@ -0,0 +1,95 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using System.IO;
30using System.Reflection;
31using System.Threading;
32using OpenMetaverse;
33using log4net;
34using Nini.Config;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.CoreModules.World.Serialiser;
39
40namespace OpenSim.Region.CoreModules.World.Archiver
41{
42 /// <summary>
43 /// This module loads and saves OpenSimulator archives
44 /// </summary>
45 public class ArchiverModule : IRegionModule, IRegionArchiverModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private Scene m_scene;
50
51 public string Name { get { return "Archiver Module"; } }
52
53 public bool IsSharedModule { get { return false; } }
54
55 public void Initialise(Scene scene, IConfigSource source)
56 {
57 m_scene = scene;
58 m_scene.RegisterModuleInterface<IRegionArchiverModule>(this);
59 }
60
61 public void PostInitialise()
62 {
63 }
64
65 public void Close()
66 {
67 }
68
69 public void ArchiveRegion(string savePath)
70 {
71 m_log.InfoFormat(
72 "[ARCHIVER]: Writing archive for region {0} to {1}", m_scene.RegionInfo.RegionName, savePath);
73
74 new ArchiveWriteRequestPreparation(m_scene, savePath).ArchiveRegion();
75 }
76
77 public void ArchiveRegion(Stream saveStream)
78 {
79 new ArchiveWriteRequestPreparation(m_scene, saveStream).ArchiveRegion();
80 }
81
82 public void DearchiveRegion(string loadPath)
83 {
84 m_log.InfoFormat(
85 "[ARCHIVER]: Loading archive to region {0} from {1}", m_scene.RegionInfo.RegionName, loadPath);
86
87 new ArchiveReadRequest(m_scene, loadPath).DearchiveRegion();
88 }
89
90 public void DearchiveRegion(Stream loadStream)
91 {
92 new ArchiveReadRequest(m_scene, loadStream).DearchiveRegion();
93 }
94 }
95}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
new file mode 100644
index 0000000..76d27ce
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
@@ -0,0 +1,143 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using System.IO;
30using System.Reflection;
31using System.Xml;
32using OpenMetaverse;
33using log4net;
34using OpenSim.Framework;
35
36namespace OpenSim.Region.CoreModules.World.Archiver
37{
38 /// <summary>
39 /// Archives assets
40 /// </summary>
41 public class AssetsArchiver
42 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 /// <summary>
46 /// Archive assets
47 /// </summary>
48 protected IDictionary<UUID, AssetBase> m_assets;
49
50 public AssetsArchiver(IDictionary<UUID, AssetBase> assets)
51 {
52 m_assets = assets;
53 }
54
55 /// <summary>
56 /// Archive the assets given to this archiver to the given archive.
57 /// </summary>
58 /// <param name="archive"></param>
59 public void Archive(TarArchiveWriter archive)
60 {
61 //WriteMetadata(archive);
62 WriteData(archive);
63 }
64
65 /// <summary>
66 /// Write an assets metadata file to the given archive
67 /// </summary>
68 /// <param name="archive"></param>
69 protected void WriteMetadata(TarArchiveWriter archive)
70 {
71 StringWriter sw = new StringWriter();
72 XmlTextWriter xtw = new XmlTextWriter(sw);
73
74 xtw.Formatting = Formatting.Indented;
75 xtw.WriteStartDocument();
76
77 xtw.WriteStartElement("assets");
78
79 foreach (UUID uuid in m_assets.Keys)
80 {
81 AssetBase asset = m_assets[uuid];
82
83 if (asset != null)
84 {
85 xtw.WriteStartElement("asset");
86
87 string extension = string.Empty;
88
89 if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.Metadata.Type))
90 {
91 extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.Metadata.Type];
92 }
93
94 xtw.WriteElementString("filename", uuid.ToString() + extension);
95
96 xtw.WriteElementString("name", asset.Metadata.Name);
97 xtw.WriteElementString("description", asset.Metadata.Description);
98 xtw.WriteElementString("asset-type", asset.Metadata.Type.ToString());
99
100 xtw.WriteEndElement();
101 }
102 }
103
104 xtw.WriteEndElement();
105
106 xtw.WriteEndDocument();
107
108 archive.AddFile("assets.xml", sw.ToString());
109 }
110
111 /// <summary>
112 /// Write asset data files to the given archive
113 /// </summary>
114 /// <param name="archive"></param>
115 protected void WriteData(TarArchiveWriter archive)
116 {
117 // It appears that gtar, at least, doesn't need the intermediate directory entries in the tar
118 //archive.AddDir("assets");
119
120 foreach (UUID uuid in m_assets.Keys)
121 {
122 AssetBase asset = m_assets[uuid];
123
124 string extension = string.Empty;
125
126 if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.Metadata.Type))
127 {
128 extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.Metadata.Type];
129 }
130 else
131 {
132 m_log.ErrorFormat(
133 "[ARCHIVER]: Unrecognized asset type {0} with uuid {1}. This asset will be saved but not reloaded",
134 asset.Metadata.Type, asset.Metadata.ID);
135 }
136
137 archive.AddFile(
138 ArchiveConstants.ASSETS_PATH + uuid.ToString() + extension,
139 asset.Data);
140 }
141 }
142 }
143}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs
new file mode 100644
index 0000000..f9909d9
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs
@@ -0,0 +1,184 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33using OpenMetaverse;
34using log4net;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications.Cache;
37
38namespace OpenSim.Region.CoreModules.World.Archiver
39{
40 /// <summary>
41 /// Dearchives assets
42 /// </summary>
43 public class AssetsDearchiver
44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 protected static System.Text.ASCIIEncoding m_asciiEncoding = new System.Text.ASCIIEncoding();
48
49 /// <summary>
50 /// Store for asset data we received before we get the metadata
51 /// </summary>
52 protected Dictionary<string, byte[]> m_assetDataAwaitingMetadata = new Dictionary<string, byte[]>();
53
54 /// <summary>
55 /// Asset metadata. Is null if asset metadata isn't yet available.
56 /// </summary>
57 protected Dictionary<string, AssetMetadata> m_metadata;
58
59 /// <summary>
60 /// Cache to which dearchived assets will be added
61 /// </summary>
62 protected IAssetCache m_cache;
63
64 public AssetsDearchiver(IAssetCache cache)
65 {
66 m_cache = cache;
67 }
68
69 /// <summary>
70 /// Add asset data to the dearchiver
71 /// </summary>
72 /// <param name="assetFilename"></param>
73 /// <param name="data"></param>
74 public void AddAssetData(string assetFilename, byte[] data)
75 {
76 if (null == m_metadata)
77 {
78 m_assetDataAwaitingMetadata[assetFilename] = data;
79 }
80 else
81 {
82 ResolveAssetData(assetFilename, data);
83 }
84 }
85
86 /// <summary>
87 /// Add asset metadata xml
88 /// </summary>
89 /// <param name="xml"></param>
90 public void AddAssetMetadata(string xml)
91 {
92 m_metadata = new Dictionary<string, AssetMetadata>();
93
94 StringReader sr = new StringReader(xml);
95 XmlTextReader reader = new XmlTextReader(sr);
96
97 reader.ReadStartElement("assets");
98 reader.Read();
99
100 while (reader.Name.Equals("asset"))
101 {
102 reader.Read();
103
104 AssetMetadata metadata = new AssetMetadata();
105
106 string filename = reader.ReadElementString("filename");
107 m_log.DebugFormat("[DEARCHIVER]: Reading node {0}", filename);
108
109 metadata.Name = reader.ReadElementString("name");
110 metadata.Description = reader.ReadElementString("description");
111 metadata.AssetType = Convert.ToSByte(reader.ReadElementString("asset-type"));
112
113 m_metadata[filename] = metadata;
114
115 // Read asset end tag
116 reader.ReadEndElement();
117
118 reader.Read();
119 }
120
121 m_log.DebugFormat("[DEARCHIVER]: Resolved {0} items of asset metadata", m_metadata.Count);
122
123 ResolvePendingAssetData();
124 }
125
126 /// <summary>
127 /// Resolve asset data that we collected before receiving the metadata
128 /// </summary>
129 protected void ResolvePendingAssetData()
130 {
131 foreach (string filename in m_assetDataAwaitingMetadata.Keys)
132 {
133 ResolveAssetData(filename, m_assetDataAwaitingMetadata[filename]);
134 }
135 }
136
137 /// <summary>
138 /// Resolve a new piece of asset data against stored metadata
139 /// </summary>
140 /// <param name="assetFilename"></param>
141 /// <param name="data"></param>
142 protected void ResolveAssetData(string assetPath, byte[] data)
143 {
144 // Right now we're nastily obtaining the UUID from the filename
145 string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
146
147 if (m_metadata.ContainsKey(filename))
148 {
149 AssetMetadata metadata = m_metadata[filename];
150
151 if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(metadata.AssetType))
152 {
153 string extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[metadata.AssetType];
154 filename = filename.Remove(filename.Length - extension.Length);
155 }
156
157 m_log.DebugFormat("[ARCHIVER]: Importing asset {0}", filename);
158
159 AssetBase asset = new AssetBase(new UUID(filename), metadata.Name);
160 asset.Metadata.Description = metadata.Description;
161 asset.Metadata.Type = metadata.AssetType;
162 asset.Data = data;
163
164 m_cache.AddAsset(asset);
165 }
166 else
167 {
168 m_log.ErrorFormat(
169 "[DEARCHIVER]: Tried to dearchive data with filename {0} without any corresponding metadata",
170 assetPath);
171 }
172 }
173
174 /// <summary>
175 /// Metadata for an asset
176 /// </summary>
177 protected struct AssetMetadata
178 {
179 public string Name;
180 public string Description;
181 public sbyte AssetType;
182 }
183 }
184}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
new file mode 100644
index 0000000..8971b6e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -0,0 +1,138 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32using OpenMetaverse;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.CoreModules.World.Archiver
40{
41 /// <summary>
42 /// Encapsulate the asynchronous requests for the assets required for an archive operation
43 /// </summary>
44 class AssetsRequest
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 /// <summary>
49 /// uuids to request
50 /// </summary>
51 protected ICollection<UUID> m_uuids;
52
53 /// <summary>
54 /// Callback used when all the assets requested have been received.
55 /// </summary>
56 protected AssetsRequestCallback m_assetsRequestCallback;
57
58 /// <summary>
59 /// Assets retrieved in this request
60 /// </summary>
61 protected Dictionary<UUID, AssetBase> m_assets = new Dictionary<UUID, AssetBase>();
62
63 /// <summary>
64 /// Maintain a list of assets that could not be found. This will be passed back to the requester.
65 /// </summary>
66 protected List<UUID> m_notFoundAssetUuids = new List<UUID>();
67
68 /// <summary>
69 /// Record the number of asset replies required so we know when we've finished
70 /// </summary>
71 private int m_repliesRequired;
72
73 /// <summary>
74 /// Asset cache used to request the assets
75 /// </summary>
76 protected IAssetCache m_assetCache;
77
78 protected internal AssetsRequest(ICollection<UUID> uuids, IAssetCache assetCache, AssetsRequestCallback assetsRequestCallback)
79 {
80 m_uuids = uuids;
81 m_assetsRequestCallback = assetsRequestCallback;
82 m_assetCache = assetCache;
83 m_repliesRequired = uuids.Count;
84 }
85
86 protected internal void Execute()
87 {
88 // We can stop here if there are no assets to fetch
89 if (m_repliesRequired == 0)
90 m_assetsRequestCallback(m_assets, m_notFoundAssetUuids);
91
92 foreach (UUID uuid in m_uuids)
93 {
94 m_assetCache.GetAsset(uuid, AssetRequestCallback, true);
95 }
96 }
97
98 /// <summary>
99 /// Called back by the asset cache when it has the asset
100 /// </summary>
101 /// <param name="assetID"></param>
102 /// <param name="asset"></param>
103 public void AssetRequestCallback(UUID assetID, AssetBase asset)
104 {
105 if (asset != null)
106 m_assets[assetID] = asset;
107 else
108 m_notFoundAssetUuids.Add(assetID);
109
110 //m_log.DebugFormat(
111 // "[ARCHIVER]: Received {0} assets and notification of {1} missing assets", m_assets.Count, m_notFoundAssetUuids.Count);
112
113 if (m_assets.Count + m_notFoundAssetUuids.Count == m_repliesRequired)
114 {
115 // We want to stop using the asset cache thread asap as we now need to do the actual work of producing the archive
116 Thread newThread = new Thread(PerformAssetsRequestCallback);
117 newThread.Name = "OpenSimulator archiving thread post assets receipt";
118 newThread.Start();
119 }
120 }
121
122 /// <summary>
123 /// Perform the callback on the original requester of the assets
124 /// </summary>
125 protected void PerformAssetsRequestCallback()
126 {
127 try
128 {
129 m_assetsRequestCallback(m_assets, m_notFoundAssetUuids);
130 }
131 catch (Exception e)
132 {
133 m_log.ErrorFormat(
134 "[ARCHIVER]: Terminating archive creation since asset requster callback failed with {0}", e);
135 }
136 }
137 }
138}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/RegionSettingsSerializer.cs b/OpenSim/Region/CoreModules/World/Archiver/RegionSettingsSerializer.cs
new file mode 100644
index 0000000..2580316
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/RegionSettingsSerializer.cs
@@ -0,0 +1,258 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Text;
31using System.Xml;
32using OpenMetaverse;
33using OpenSim.Framework;
34
35namespace OpenSim.Region.CoreModules.World.Archiver
36{
37 /// <summary>
38 /// Serialize and deserialize region settings for an archive file format.
39 /// </summary>
40 /// We didn't simply use automatic .NET serializagion for OpenSim.Framework.RegionSettings since this is really
41 /// a file format rather than an object serialization.
42 /// TODO: However, we could still have used separate non-framework classes here to read and write the xml
43 /// automatically rather than laboriously doing it by hand using XmlTextReader and Writer. Should switch to this
44 /// in the future.
45 public class RegionSettingsSerializer
46 {
47 protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
48
49 /// <summary>
50 /// Deserialize region settings
51 /// </summary>
52 /// <param name="serializedSettings"></param>
53 /// <returns></returns>
54 /// <exception cref="System.Xml.XmlException"></exception>
55 public static RegionSettings Deserialize(byte[] serializedSettings)
56 {
57 return Deserialize(m_asciiEncoding.GetString(serializedSettings, 0, serializedSettings.Length));
58 }
59
60 /// <summary>
61 /// Deserialize region settings
62 /// </summary>
63 /// <param name="serializedSettings"></param>
64 /// <returns></returns>
65 /// <exception cref="System.Xml.XmlException"></exception>
66 public static RegionSettings Deserialize(string serializedSettings)
67 {
68 RegionSettings settings = new RegionSettings();
69
70 StringReader sr = new StringReader(serializedSettings);
71 XmlTextReader xtr = new XmlTextReader(sr);
72
73 xtr.ReadStartElement("RegionSettings");
74
75 xtr.ReadStartElement("General");
76
77 while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement)
78 {
79 switch (xtr.Name)
80 {
81 case "AllowDamage":
82 settings.AllowDamage = bool.Parse(xtr.ReadElementContentAsString());
83 break;
84 case "AllowLandResell":
85 settings.AllowLandResell = bool.Parse(xtr.ReadElementContentAsString());
86 break;
87 case "AllowLandJoinDivide":
88 settings.AllowLandJoinDivide = bool.Parse(xtr.ReadElementContentAsString());
89 break;
90 case "BlockFly":
91 settings.BlockFly = bool.Parse(xtr.ReadElementContentAsString());
92 break;
93 case "BlockLandShowInSearch":
94 settings.BlockShowInSearch = bool.Parse(xtr.ReadElementContentAsString());
95 break;
96 case "BlockTerraform":
97 settings.BlockTerraform = bool.Parse(xtr.ReadElementContentAsString());
98 break;
99 case "DisableCollisions":
100 settings.DisableCollisions = bool.Parse(xtr.ReadElementContentAsString());
101 break;
102 case "DisablePhysics":
103 settings.DisablePhysics = bool.Parse(xtr.ReadElementContentAsString());
104 break;
105 case "DisableScripts":
106 settings.DisableScripts = bool.Parse(xtr.ReadElementContentAsString());
107 break;
108 case "MaturityRating":
109 settings.Maturity = int.Parse(xtr.ReadElementContentAsString());
110 break;
111 case "RestrictPushing":
112 settings.RestrictPushing = bool.Parse(xtr.ReadElementContentAsString());
113 break;
114 case "AgentLimit":
115 settings.AgentLimit = int.Parse(xtr.ReadElementContentAsString());
116 break;
117 case "ObjectBonus":
118 settings.ObjectBonus = double.Parse(xtr.ReadElementContentAsString());
119 break;
120 }
121 }
122
123 xtr.ReadEndElement();
124 xtr.ReadStartElement("GroundTextures");
125
126 while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement)
127 {
128 switch (xtr.Name)
129 {
130 case "Texture1":
131 settings.TerrainTexture1 = UUID.Parse(xtr.ReadElementContentAsString());
132 break;
133 case "Texture2":
134 settings.TerrainTexture2 = UUID.Parse(xtr.ReadElementContentAsString());
135 break;
136 case "Texture3":
137 settings.TerrainTexture3 = UUID.Parse(xtr.ReadElementContentAsString());
138 break;
139 case "Texture4":
140 settings.TerrainTexture4 = UUID.Parse(xtr.ReadElementContentAsString());
141 break;
142 case "ElevationLowSW":
143 settings.Elevation1SW = double.Parse(xtr.ReadElementContentAsString());
144 break;
145 case "ElevationLowNW":
146 settings.Elevation1NW = double.Parse(xtr.ReadElementContentAsString());
147 break;
148 case "ElevationLowSE":
149 settings.Elevation1SE = double.Parse(xtr.ReadElementContentAsString());
150 break;
151 case "ElevationLowNE":
152 settings.Elevation1NE = double.Parse(xtr.ReadElementContentAsString());
153 break;
154 case "ElevationHighSW":
155 settings.Elevation1SW = double.Parse(xtr.ReadElementContentAsString());
156 break;
157 case "ElevationHighNW":
158 settings.Elevation2NW = double.Parse(xtr.ReadElementContentAsString());
159 break;
160 case "ElevationHighSE":
161 settings.Elevation2SE = double.Parse(xtr.ReadElementContentAsString());
162 break;
163 case "ElevationHighNE":
164 settings.Elevation2NE = double.Parse(xtr.ReadElementContentAsString());
165 break;
166 }
167 }
168
169 xtr.ReadEndElement();
170 xtr.ReadStartElement("Terrain");
171
172 while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement)
173 {
174 switch (xtr.Name)
175 {
176 case "WaterHeight":
177 settings.WaterHeight = double.Parse(xtr.ReadElementContentAsString());
178 break;
179 case "TerrainRaiseLimit":
180 settings.TerrainRaiseLimit = double.Parse(xtr.ReadElementContentAsString());
181 break;
182 case "TerrainLowerLimit":
183 settings.TerrainLowerLimit = double.Parse(xtr.ReadElementContentAsString());
184 break;
185 case "UseEstateSun":
186 settings.UseEstateSun = bool.Parse(xtr.ReadElementContentAsString());
187 break;
188 case "FixedSun":
189 settings.FixedSun = bool.Parse(xtr.ReadElementContentAsString());
190 break;
191 }
192 }
193
194 xtr.Close();
195 sr.Close();
196
197 return settings;
198 }
199
200 public static string Serialize(RegionSettings settings)
201 {
202 StringWriter sw = new StringWriter();
203 XmlTextWriter xtw = new XmlTextWriter(sw);
204 xtw.Formatting = Formatting.Indented;
205 xtw.WriteStartDocument();
206
207 xtw.WriteStartElement("RegionSettings");
208
209 xtw.WriteStartElement("General");
210 xtw.WriteElementString("AllowDamage", settings.AllowDamage.ToString());
211 xtw.WriteElementString("AllowLandResell", settings.AllowLandResell.ToString());
212 xtw.WriteElementString("AllowLandJoinDivide", settings.AllowLandJoinDivide.ToString());
213 xtw.WriteElementString("BlockFly", settings.BlockFly.ToString());
214 xtw.WriteElementString("BlockLandShowInSearch", settings.BlockShowInSearch.ToString());
215 xtw.WriteElementString("BlockTerraform", settings.BlockTerraform.ToString());
216 xtw.WriteElementString("DisableCollisions", settings.DisableCollisions.ToString());
217 xtw.WriteElementString("DisablePhysics", settings.DisablePhysics.ToString());
218 xtw.WriteElementString("DisableScripts", settings.DisableScripts.ToString());
219 xtw.WriteElementString("MaturityRating", settings.Maturity.ToString());
220 xtw.WriteElementString("RestrictPushing", settings.RestrictPushing.ToString());
221 xtw.WriteElementString("AgentLimit", settings.AgentLimit.ToString());
222 xtw.WriteElementString("ObjectBonus", settings.ObjectBonus.ToString());
223 xtw.WriteEndElement();
224
225 xtw.WriteStartElement("GroundTextures");
226 xtw.WriteElementString("Texture1", settings.TerrainTexture1.ToString());
227 xtw.WriteElementString("Texture2", settings.TerrainTexture2.ToString());
228 xtw.WriteElementString("Texture3", settings.TerrainTexture3.ToString());
229 xtw.WriteElementString("Texture4", settings.TerrainTexture4.ToString());
230 xtw.WriteElementString("ElevationLowSW", settings.Elevation1SW.ToString());
231 xtw.WriteElementString("ElevationLowNW", settings.Elevation1NW.ToString());
232 xtw.WriteElementString("ElevationLowSE", settings.Elevation1SE.ToString());
233 xtw.WriteElementString("ElevationLowNE", settings.Elevation1NE.ToString());
234 xtw.WriteElementString("ElevationHighSW", settings.Elevation2SW.ToString());
235 xtw.WriteElementString("ElevationHighNW", settings.Elevation2NW.ToString());
236 xtw.WriteElementString("ElevationHighSE", settings.Elevation2SE.ToString());
237 xtw.WriteElementString("ElevationHighNE", settings.Elevation2NE.ToString());
238 xtw.WriteEndElement();
239
240 xtw.WriteStartElement("Terrain");
241 xtw.WriteElementString("WaterHeight", settings.WaterHeight.ToString());
242 xtw.WriteElementString("TerrainRaiseLimit", settings.TerrainRaiseLimit.ToString());
243 xtw.WriteElementString("TerrainLowerLimit", settings.TerrainLowerLimit.ToString());
244 xtw.WriteElementString("UseEstateSun", settings.UseEstateSun.ToString());
245 xtw.WriteElementString("FixedSun", settings.FixedSun.ToString());
246 // XXX: Need to expose interface to get sun phase information from sun module
247 // xtw.WriteStartElement("SunPhase",
248 xtw.WriteEndElement();
249
250 xtw.WriteEndElement();
251
252 xtw.Close();
253 sw.Close();
254
255 return sw.ToString();
256 }
257 }
258}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs
new file mode 100644
index 0000000..506d770
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs
@@ -0,0 +1,195 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using System.Text;
32using log4net;
33
34namespace OpenSim.Region.CoreModules.World.Archiver
35{
36 /// <summary>
37 /// Temporary code to do the bare minimum required to read a tar archive for our purposes
38 /// </summary>
39 public class TarArchiveReader
40 {
41 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 public enum TarEntryType
44 {
45 TYPE_UNKNOWN = 0,
46 TYPE_NORMAL_FILE = 1,
47 TYPE_HARD_LINK = 2,
48 TYPE_SYMBOLIC_LINK = 3,
49 TYPE_CHAR_SPECIAL = 4,
50 TYPE_BLOCK_SPECIAL = 5,
51 TYPE_DIRECTORY = 6,
52 TYPE_FIFO = 7,
53 TYPE_CONTIGUOUS_FILE = 8,
54 }
55
56 protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
57
58 /// <summary>
59 /// Binary reader for the underlying stream
60 /// </summary>
61 protected BinaryReader m_br;
62
63 /// <summary>
64 /// Used to trim off null chars
65 /// </summary>
66 protected char[] m_nullCharArray = new char[] { '\0' };
67
68 /// <summary>
69 /// Generate a tar reader which reads from the given stream.
70 /// </summary>
71 /// <param name="s"></param>
72 public TarArchiveReader(Stream s)
73 {
74 m_br = new BinaryReader(s);
75 }
76
77 /// <summary>
78 /// Read the next entry in the tar file.
79 /// </summary>
80 /// <param name="filePath"></param>
81 /// <returns>the data for the entry. Returns null if there are no more entries</returns>
82 public byte[] ReadEntry(out string filePath, out TarEntryType entryType)
83 {
84 filePath = String.Empty;
85 entryType = TarEntryType.TYPE_UNKNOWN;
86 TarHeader header = ReadHeader();
87
88 if (null == header)
89 return null;
90
91 entryType = header.EntryType;
92 filePath = header.FilePath;
93 byte[] data = m_br.ReadBytes(header.FileSize);
94
95 //m_log.DebugFormat("[TAR ARCHIVE READER]: filePath {0}, fileSize {1}", filePath, header.FileSize);
96
97 // Read the rest of the empty padding in the 512 byte block
98 if (header.FileSize % 512 != 0)
99 {
100 int paddingLeft = 512 - (header.FileSize % 512);
101
102 //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft);
103
104 m_br.ReadBytes(paddingLeft);
105 }
106
107 return data;
108 }
109
110 /// <summary>
111 /// Read the next 512 byte chunk of data as a tar header.
112 /// </summary>
113 /// <returns>A tar header struct. null if we have reached the end of the archive.</returns>
114 protected TarHeader ReadHeader()
115 {
116 byte[] header = m_br.ReadBytes(512);
117
118 // If we've reached the end of the archive we'll be in null block territory, which means
119 // the next byte will be 0
120 if (header[0] == 0)
121 return null;
122
123 TarHeader tarHeader = new TarHeader();
124
125 tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
126 tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
127 tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
128
129 switch (header[156])
130 {
131 case 0:
132 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
133 break;
134 case (byte)'0':
135 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
136 break;
137 case (byte)'1':
138 tarHeader.EntryType = TarEntryType.TYPE_HARD_LINK;
139 break;
140 case (byte)'2':
141 tarHeader.EntryType = TarEntryType.TYPE_SYMBOLIC_LINK;
142 break;
143 case (byte)'3':
144 tarHeader.EntryType = TarEntryType.TYPE_CHAR_SPECIAL;
145 break;
146 case (byte)'4':
147 tarHeader.EntryType = TarEntryType.TYPE_BLOCK_SPECIAL;
148 break;
149 case (byte)'5':
150 tarHeader.EntryType = TarEntryType.TYPE_DIRECTORY;
151 break;
152 case (byte)'6':
153 tarHeader.EntryType = TarEntryType.TYPE_FIFO;
154 break;
155 case (byte)'7':
156 tarHeader.EntryType = TarEntryType.TYPE_CONTIGUOUS_FILE;
157 break;
158 }
159
160 return tarHeader;
161 }
162
163 public void Close()
164 {
165 m_br.Close();
166 }
167
168 /// <summary>
169 /// Convert octal bytes to a decimal representation
170 /// </summary>
171 /// <param name="bytes"></param>
172 /// <returns></returns>
173 public static int ConvertOctalBytesToDecimal(byte[] bytes, int startIndex, int count)
174 {
175 string oString = m_asciiEncoding.GetString(bytes, startIndex, count);
176
177 int d = 0;
178
179 foreach (char c in oString)
180 {
181 d <<= 3;
182 d |= c - '0';
183 }
184
185 return d;
186 }
187 }
188
189 public class TarHeader
190 {
191 public string FilePath;
192 public int FileSize;
193 public TarArchiveReader.TarEntryType EntryType;
194 }
195}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs
new file mode 100644
index 0000000..437939e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs
@@ -0,0 +1,202 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Text;
32using System.Reflection;
33using log4net;
34
35namespace OpenSim.Region.CoreModules.World.Archiver
36{
37 /// <summary>
38 /// Temporary code to produce a tar archive in tar v7 format
39 /// </summary>
40 public class TarArchiveWriter
41 {
42 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 protected Dictionary<string, byte[]> m_files = new Dictionary<string, byte[]>();
45
46 protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
47
48 /// <summary>
49 /// Add a directory to the tar archive. We can only handle one path level right now!
50 /// </summary>
51 /// <param name="dirName"></param>
52 public void AddDir(string dirName)
53 {
54 // Directories are signalled by a final /
55 if (!dirName.EndsWith("/"))
56 dirName += "/";
57
58 AddFile(dirName, new byte[0]);
59 }
60
61 /// <summary>
62 /// Add a file to the tar archive
63 /// </summary>
64 /// <param name="filePath"></param>
65 /// <param name="data"></param>
66 public void AddFile(string filePath, string data)
67 {
68 AddFile(filePath, m_asciiEncoding.GetBytes(data));
69 }
70
71 /// <summary>
72 /// Add a file to the tar archive
73 /// </summary>
74 /// <param name="filePath"></param>
75 /// <param name="data"></param>
76 public void AddFile(string filePath, byte[] data)
77 {
78 m_files[filePath] = data;
79 }
80
81 /// <summary>
82 /// Write the raw tar archive data to a stream. The stream will be closed on completion.
83 /// </summary>
84 /// <param name="s">Stream to which to write the data</param>
85 /// <returns></returns>
86 public void WriteTar(Stream s)
87 {
88 BinaryWriter bw = new BinaryWriter(s);
89
90 foreach (string filePath in m_files.Keys)
91 {
92 byte[] header = new byte[512];
93 byte[] data = m_files[filePath];
94
95 // file path field (100)
96 byte[] nameBytes = m_asciiEncoding.GetBytes(filePath);
97 int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length;
98 Array.Copy(nameBytes, header, nameSize);
99
100 // file mode (8)
101 byte[] modeBytes = m_asciiEncoding.GetBytes("0000777");
102 Array.Copy(modeBytes, 0, header, 100, 7);
103
104 // owner user id (8)
105 byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764");
106 Array.Copy(ownerIdBytes, 0, header, 108, 7);
107
108 // group user id (8)
109 byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764");
110 Array.Copy(groupIdBytes, 0, header, 116, 7);
111
112 // file size in bytes (12)
113 int fileSize = data.Length;
114 //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize);
115
116 byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11);
117
118 Array.Copy(fileSizeBytes, 0, header, 124, 11);
119
120 // last modification time (12)
121 byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332");
122 Array.Copy(lastModTimeBytes, 0, header, 136, 11);
123
124 // link indicator (1)
125 //header[156] = m_asciiEncoding.GetBytes("0")[0];
126 if (filePath.EndsWith("/"))
127 {
128 header[156] = m_asciiEncoding.GetBytes("5")[0];
129 }
130 else
131 {
132 header[156] = 0;
133 }
134
135 Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7);
136 Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7);
137
138 // check sum for header block (8) [calculated last]
139 Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8);
140
141 int checksum = 0;
142 foreach (byte b in header)
143 {
144 checksum += b;
145 }
146
147 //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum);
148
149 byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6);
150
151 Array.Copy(checkSumBytes, 0, header, 148, 6);
152
153 header[154] = 0;
154
155 // Write out header
156 bw.Write(header);
157
158 // Write out data
159 bw.Write(data);
160
161 if (data.Length % 512 != 0)
162 {
163 int paddingRequired = 512 - (data.Length % 512);
164
165 //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired);
166
167 byte[] padding = new byte[paddingRequired];
168 bw.Write(padding);
169 }
170 }
171
172 //m_log.Debug("[TAR ARCHIVE WRITER]: Writing final consecutive 0 blocks");
173
174 // Write two consecutive 0 blocks to end the archive
175 byte[] finalZeroPadding = new byte[1024];
176 bw.Write(finalZeroPadding);
177
178 bw.Flush();
179 bw.Close();
180 }
181
182 public static byte[] ConvertDecimalToPaddedOctalBytes(int d, int padding)
183 {
184 string oString = "";
185
186 while (d > 0)
187 {
188 oString = Convert.ToString((byte)'0' + d & 7) + oString;
189 d >>= 3;
190 }
191
192 while (oString.Length < padding)
193 {
194 oString = "0" + oString;
195 }
196
197 byte[] oBytes = m_asciiEncoding.GetBytes(oString);
198
199 return oBytes;
200 }
201 }
202}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
new file mode 100644
index 0000000..a14e0f6
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -0,0 +1,188 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Threading;
31using NUnit.Framework;
32using NUnit.Framework.SyntaxHelpers;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.CoreModules.World.Archiver;
37using OpenSim.Region.CoreModules.World.Serialiser;
38using OpenSim.Region.CoreModules.World.Terrain;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Tests.Common.Setup;
41
42namespace OpenSim.Region.CoreModules.World.Archiver.Tests
43{
44 [TestFixture]
45 public class ArchiverTests
46 {
47 private EventWaitHandle m_waitHandle = new AutoResetEvent(false);
48
49 private void SaveCompleted(string errorMessage)
50 {
51 m_waitHandle.Set();
52 }
53
54 /// <summary>
55 /// Test saving a V0.2 OpenSim Region Archive.
56 /// </summary>
57 [Test]
58 public void TestSaveOarV0p2()
59 {
60 log4net.Config.XmlConfigurator.Configure();
61
62 ArchiverModule archiverModule = new ArchiverModule();
63 SerialiserModule serialiserModule = new SerialiserModule();
64 TerrainModule terrainModule = new TerrainModule();
65
66 Scene scene = SceneSetupHelpers.SetupScene();
67 SceneSetupHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule);
68
69 SceneObjectPart part1;
70
71 // Create and add prim 1
72 {
73 string partName = "My Little Pony";
74 UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000015");
75 PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
76 Vector3 groupPosition = new Vector3(10, 20, 30);
77 Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
78 Vector3 offsetPosition = new Vector3(5, 10, 15);
79
80 part1
81 = new SceneObjectPart(
82 ownerId, shape, groupPosition, rotationOffset, offsetPosition);
83 part1.Name = partName;
84
85 scene.AddNewSceneObject(new SceneObjectGroup(part1), false);
86 }
87
88 SceneObjectPart part2;
89
90 // Create and add prim 2
91 {
92 string partName = "Action Man";
93 UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000016");
94 PrimitiveBaseShape shape = PrimitiveBaseShape.CreateCylinder();
95 Vector3 groupPosition = new Vector3(90, 80, 70);
96 Quaternion rotationOffset = new Quaternion(60, 70, 80, 90);
97 Vector3 offsetPosition = new Vector3(20, 25, 30);
98
99 part2
100 = new SceneObjectPart(
101 ownerId, shape, groupPosition, rotationOffset, offsetPosition);
102 part2.Name = partName;
103
104 scene.AddNewSceneObject(new SceneObjectGroup(part2), false);
105 }
106
107 MemoryStream archiveWriteStream = new MemoryStream();
108
109 scene.EventManager.OnOarFileSaved += SaveCompleted;
110 archiverModule.ArchiveRegion(archiveWriteStream);
111 m_waitHandle.WaitOne(60000, true);
112
113 byte[] archive = archiveWriteStream.ToArray();
114 MemoryStream archiveReadStream = new MemoryStream(archive);
115 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
116
117 bool gotControlFile = false;
118 bool gotObject1File = false;
119 bool gotObject2File = false;
120 string expectedObject1FileName = string.Format(
121 "{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
122 part1.Name,
123 Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z),
124 part1.UUID);
125 string expectedObject2FileName = string.Format(
126 "{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
127 part2.Name,
128 Math.Round(part2.GroupPosition.X), Math.Round(part2.GroupPosition.Y), Math.Round(part2.GroupPosition.Z),
129 part2.UUID);
130
131 string filePath;
132 TarArchiveReader.TarEntryType tarEntryType;
133
134 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
135 {
136 if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
137 {
138 gotControlFile = true;
139 }
140 else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
141 {
142 string fileName = filePath.Remove(0, ArchiveConstants.OBJECTS_PATH.Length);
143
144 if (fileName.StartsWith(part1.Name))
145 {
146 Assert.That(fileName, Is.EqualTo(expectedObject1FileName));
147 gotObject1File = true;
148 }
149 else if (fileName.StartsWith(part2.Name))
150 {
151 Assert.That(fileName, Is.EqualTo(expectedObject2FileName));
152 gotObject2File = true;
153 }
154 }
155 }
156
157 Assert.That(gotControlFile, Is.True, "No control file in archive");
158 Assert.That(gotObject1File, Is.True, "No object1 file in archive");
159 Assert.That(gotObject2File, Is.True, "No object2 file in archive");
160
161 // TODO: Test presence of more files and contents of files.
162 }
163
164 /// <summary>
165 /// Test loading a V0.2 OpenSim Region Archive. Does not yet do what it says on the tin.
166 /// </summary>
167 [Test]
168 public void TestLoadOarV0p2()
169 {
170 MemoryStream archiveWriteStream = new MemoryStream();
171 TarArchiveWriter tar = new TarArchiveWriter();
172
173 tar.AddFile(ArchiveConstants.CONTROL_FILE_PATH, ArchiveWriteRequestExecution.Create0p2ControlFile());
174 tar.WriteTar(archiveWriteStream);
175
176 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
177
178 ArchiverModule archiverModule = new ArchiverModule();
179
180 Scene scene = SceneSetupHelpers.SetupScene();
181 SceneSetupHelpers.SetupSceneModules(scene, archiverModule);
182
183 archiverModule.DearchiveRegion(archiveReadStream);
184
185 // TODO: Okay, so nothing is tested yet apart from the fact that it doesn't blow up
186 }
187 }
188} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
new file mode 100644
index 0000000..8b15308
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -0,0 +1,1012 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Threading;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.CoreModules.World.Estate
39{
40 public class EstateManagementModule : IEstateModule
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private delegate void LookupUUIDS(List<UUID> uuidLst);
45
46 private Scene m_scene;
47
48 private EstateTerrainXferHandler TerrainUploader = null;
49
50 #region Packet Data Responders
51
52 private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice)
53 {
54 uint sun = 0;
55
56 if (!m_scene.RegionInfo.EstateSettings.UseGlobalTime)
57 sun=(uint)(m_scene.RegionInfo.EstateSettings.SunPosition*1024.0) + 0x1800;
58 UUID estateOwner;
59 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero)
60 estateOwner = m_scene.RegionInfo.EstateSettings.EstateOwner;
61 else
62 estateOwner = m_scene.RegionInfo.MasterAvatarAssignedUUID;
63
64 if (m_scene.Permissions.IsGod(remote_client.AgentId))
65 estateOwner = remote_client.AgentId;
66
67 remote_client.SendDetailedEstateData(invoice,
68 m_scene.RegionInfo.EstateSettings.EstateName,
69 m_scene.RegionInfo.EstateSettings.EstateID,
70 m_scene.RegionInfo.EstateSettings.ParentEstateID,
71 GetEstateFlags(),
72 sun,
73 m_scene.RegionInfo.RegionSettings.Covenant,
74 m_scene.RegionInfo.EstateSettings.AbuseEmail,
75 estateOwner);
76
77 remote_client.SendEstateManagersList(invoice,
78 m_scene.RegionInfo.EstateSettings.EstateManagers,
79 m_scene.RegionInfo.EstateSettings.EstateID);
80
81 remote_client.SendBannedUserList(invoice,
82 m_scene.RegionInfo.EstateSettings.EstateBans,
83 m_scene.RegionInfo.EstateSettings.EstateID);
84 }
85
86 private void estateSetRegionInfoHandler(bool blockTerraform, bool noFly, bool allowDamage, bool blockLandResell, int maxAgents, float objectBonusFactor,
87 int matureLevel, bool restrictPushObject, bool allowParcelChanges)
88 {
89 if (blockTerraform)
90 m_scene.RegionInfo.RegionSettings.BlockTerraform = true;
91 else
92 m_scene.RegionInfo.RegionSettings.BlockTerraform = false;
93
94 if (noFly)
95 m_scene.RegionInfo.RegionSettings.BlockFly = true;
96 else
97 m_scene.RegionInfo.RegionSettings.BlockFly = false;
98
99 if (allowDamage)
100 m_scene.RegionInfo.RegionSettings.AllowDamage = true;
101 else
102 m_scene.RegionInfo.RegionSettings.AllowDamage = false;
103
104 if (blockLandResell)
105 m_scene.RegionInfo.RegionSettings.AllowLandResell = false;
106 else
107 m_scene.RegionInfo.RegionSettings.AllowLandResell = true;
108
109 m_scene.RegionInfo.RegionSettings.AgentLimit = (byte) maxAgents;
110
111 m_scene.RegionInfo.RegionSettings.ObjectBonus = objectBonusFactor;
112
113 if (matureLevel <= 13)
114 m_scene.RegionInfo.RegionSettings.Maturity = 0;
115 else
116 m_scene.RegionInfo.RegionSettings.Maturity = 1;
117
118 if (restrictPushObject)
119 m_scene.RegionInfo.RegionSettings.RestrictPushing = true;
120 else
121 m_scene.RegionInfo.RegionSettings.RestrictPushing = false;
122
123 if (allowParcelChanges)
124 m_scene.RegionInfo.RegionSettings.AllowLandJoinDivide = true;
125 else
126 m_scene.RegionInfo.RegionSettings.AllowLandJoinDivide = false;
127
128 m_scene.RegionInfo.RegionSettings.Save();
129
130 sendRegionInfoPacketToAll();
131 }
132
133 public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int corner, UUID texture)
134 {
135 if (texture == UUID.Zero)
136 return;
137
138 switch (corner)
139 {
140 case 0:
141 m_scene.RegionInfo.RegionSettings.TerrainTexture1 = texture;
142 break;
143 case 1:
144 m_scene.RegionInfo.RegionSettings.TerrainTexture2 = texture;
145 break;
146 case 2:
147 m_scene.RegionInfo.RegionSettings.TerrainTexture3 = texture;
148 break;
149 case 3:
150 m_scene.RegionInfo.RegionSettings.TerrainTexture4 = texture;
151 break;
152 }
153 m_scene.RegionInfo.RegionSettings.Save();
154 }
155
156 public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue)
157 {
158 switch (corner)
159 {
160 case 0:
161 m_scene.RegionInfo.RegionSettings.Elevation1SW = lowValue;
162 m_scene.RegionInfo.RegionSettings.Elevation2SW = highValue;
163 break;
164 case 1:
165 m_scene.RegionInfo.RegionSettings.Elevation1NW = lowValue;
166 m_scene.RegionInfo.RegionSettings.Elevation2NW = highValue;
167 break;
168 case 2:
169 m_scene.RegionInfo.RegionSettings.Elevation1SE = lowValue;
170 m_scene.RegionInfo.RegionSettings.Elevation2SE = highValue;
171 break;
172 case 3:
173 m_scene.RegionInfo.RegionSettings.Elevation1NE = lowValue;
174 m_scene.RegionInfo.RegionSettings.Elevation2NE = highValue;
175 break;
176 }
177 m_scene.RegionInfo.RegionSettings.Save();
178 }
179
180 private void handleCommitEstateTerrainTextureRequest(IClientAPI remoteClient)
181 {
182 sendRegionHandshakeToAll();
183 }
184
185 public void setRegionTerrainSettings(float WaterHeight,
186 float TerrainRaiseLimit, float TerrainLowerLimit,
187 bool UseEstateSun, bool UseFixedSun, float SunHour,
188 bool UseGlobal, bool EstateFixedSun, float EstateSunHour)
189 {
190 // Water Height
191 m_scene.RegionInfo.RegionSettings.WaterHeight = WaterHeight;
192
193 // Terraforming limits
194 m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit = TerrainRaiseLimit;
195 m_scene.RegionInfo.RegionSettings.TerrainLowerLimit = TerrainLowerLimit;
196
197 // Time of day / fixed sun
198 m_scene.RegionInfo.RegionSettings.UseEstateSun = UseEstateSun;
199 m_scene.RegionInfo.RegionSettings.FixedSun = UseFixedSun;
200 m_scene.RegionInfo.RegionSettings.SunPosition = SunHour;
201
202 m_scene.EventManager.TriggerEstateToolsTimeUpdate(m_scene.RegionInfo.RegionHandle, UseFixedSun, UseEstateSun, SunHour);
203
204 //m_log.Debug("[ESTATE]: UFS: " + UseFixedSun.ToString());
205 //m_log.Debug("[ESTATE]: SunHour: " + SunHour.ToString());
206
207 sendRegionInfoPacketToAll();
208 m_scene.RegionInfo.RegionSettings.Save();
209 }
210
211 private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds)
212 {
213 m_scene.Restart(timeInSeconds);
214 }
215
216 private void handleChangeEstateCovenantRequest(IClientAPI remoteClient, UUID estateCovenantID)
217 {
218 m_scene.RegionInfo.RegionSettings.Covenant = estateCovenantID;
219 m_scene.RegionInfo.RegionSettings.Save();
220 }
221
222 private void handleEstateAccessDeltaRequest(IClientAPI remote_client, UUID invoice, int estateAccessType, UUID user)
223 {
224 // EstateAccessDelta handles Estate Managers, Sim Access, Sim Banlist, allowed Groups.. etc.
225
226 if (user == m_scene.RegionInfo.EstateSettings.EstateOwner)
227 return; // never process EO
228 if (user == m_scene.RegionInfo.MasterAvatarAssignedUUID)
229 return; // never process owner
230
231 switch (estateAccessType)
232 {
233 case 64:
234 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
235 {
236 EstateBan[] banlistcheck = m_scene.RegionInfo.EstateSettings.EstateBans;
237
238 bool alreadyInList = false;
239
240 for (int i = 0; i < banlistcheck.Length; i++)
241 {
242 if (user == banlistcheck[i].bannedUUID)
243 {
244 alreadyInList = true;
245 break;
246 }
247
248 }
249 if (!alreadyInList)
250 {
251
252 EstateBan item = new EstateBan();
253
254 item.bannedUUID = user;
255 item.estateID = m_scene.RegionInfo.EstateSettings.EstateID;
256 item.bannedIP = "0.0.0.0";
257 item.bannedIPHostMask = "0.0.0.0";
258
259 m_scene.RegionInfo.EstateSettings.AddBan(item);
260 m_scene.RegionInfo.EstateSettings.Save();
261
262 ScenePresence s = m_scene.GetScenePresence(user);
263 if (s != null)
264 {
265 if (!s.IsChildAgent)
266 {
267 s.ControllingClient.SendTeleportLocationStart();
268 m_scene.TeleportClientHome(user, s.ControllingClient);
269 }
270 }
271
272 }
273 else
274 {
275 remote_client.SendAlertMessage("User is already on the region ban list");
276 }
277 //m_scene.RegionInfo.regionBanlist.Add(Manager(user);
278 remote_client.SendBannedUserList(invoice, m_scene.RegionInfo.EstateSettings.EstateBans, m_scene.RegionInfo.EstateSettings.EstateID);
279 }
280 else
281 {
282 remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
283 }
284 break;
285 case 128:
286 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
287 {
288 EstateBan[] banlistcheck = m_scene.RegionInfo.EstateSettings.EstateBans;
289
290 bool alreadyInList = false;
291 EstateBan listitem = null;
292
293 for (int i = 0; i < banlistcheck.Length; i++)
294 {
295 if (user == banlistcheck[i].bannedUUID)
296 {
297 alreadyInList = true;
298 listitem = banlistcheck[i];
299 break;
300 }
301
302 }
303 if (alreadyInList && listitem != null)
304 {
305 m_scene.RegionInfo.EstateSettings.RemoveBan(listitem.bannedUUID);
306 m_scene.RegionInfo.EstateSettings.Save();
307 }
308 else
309 {
310 remote_client.SendAlertMessage("User is not on the region ban list");
311 }
312 //m_scene.RegionInfo.regionBanlist.Add(Manager(user);
313 remote_client.SendBannedUserList(invoice, m_scene.RegionInfo.EstateSettings.EstateBans, m_scene.RegionInfo.EstateSettings.EstateID);
314 }
315 else
316 {
317 remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
318 }
319 break;
320 case 256:
321
322 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions())
323 {
324 m_scene.RegionInfo.EstateSettings.AddEstateManager(user);
325 m_scene.RegionInfo.EstateSettings.Save();
326 remote_client.SendEstateManagersList(invoice, m_scene.RegionInfo.EstateSettings.EstateManagers, m_scene.RegionInfo.EstateSettings.EstateID);
327 }
328 else
329 {
330 remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
331 }
332
333 break;
334 case 512:
335 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions())
336 {
337 m_scene.RegionInfo.EstateSettings.RemoveEstateManager(user);
338 m_scene.RegionInfo.EstateSettings.Save();
339
340 remote_client.SendEstateManagersList(invoice, m_scene.RegionInfo.EstateSettings.EstateManagers, m_scene.RegionInfo.EstateSettings.EstateID);
341 }
342 else
343 {
344 remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
345 }
346 break;
347
348 default:
349
350 m_log.ErrorFormat("EstateOwnerMessage: Unknown EstateAccessType requested in estateAccessDelta: {0}", estateAccessType.ToString());
351 break;
352 }
353 }
354
355 private void SendSimulatorBlueBoxMessage(
356 IClientAPI remote_client, UUID invoice, UUID senderID, UUID sessionID, string senderName, string message)
357 {
358 IDialogModule dm = m_scene.RequestModuleInterface<IDialogModule>();
359
360 if (dm != null)
361 dm.SendNotificationToUsersInRegion(senderID, senderName, message);
362 }
363
364 private void SendEstateBlueBoxMessage(
365 IClientAPI remote_client, UUID invoice, UUID senderID, UUID sessionID, string senderName, string message)
366 {
367 IDialogModule dm = m_scene.RequestModuleInterface<IDialogModule>();
368
369 if (dm != null)
370 dm.SendNotificationToUsersInEstate(senderID, senderName, message);
371 }
372
373 private void handleEstateDebugRegionRequest(IClientAPI remote_client, UUID invoice, UUID senderID, bool scripted, bool collisionEvents, bool physics)
374 {
375 if (physics)
376 m_scene.RegionInfo.RegionSettings.DisablePhysics = true;
377 else
378 m_scene.RegionInfo.RegionSettings.DisablePhysics = false;
379
380 if (scripted)
381 m_scene.RegionInfo.RegionSettings.DisableScripts = true;
382 else
383 m_scene.RegionInfo.RegionSettings.DisableScripts = false;
384
385 if (collisionEvents)
386 m_scene.RegionInfo.RegionSettings.DisableCollisions = true;
387 else
388 m_scene.RegionInfo.RegionSettings.DisableCollisions = false;
389
390
391 m_scene.RegionInfo.RegionSettings.Save();
392
393 m_scene.SetSceneCoreDebug(scripted, collisionEvents, physics);
394 }
395
396 private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey)
397 {
398 if (prey != UUID.Zero)
399 {
400 ScenePresence s = m_scene.GetScenePresence(prey);
401 if (s != null)
402 {
403 s.ControllingClient.SendTeleportLocationStart();
404 m_scene.TeleportClientHome(prey, s.ControllingClient);
405 }
406 }
407 }
408
409 private void handleEstateTeleportAllUsersHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID)
410 {
411 // Get a fresh list that will not change as people get teleported away
412 List<ScenePresence> prescences = m_scene.GetScenePresences();
413 foreach (ScenePresence p in prescences)
414 {
415 if (p.UUID != senderID)
416 {
417 // make sure they are still there, we could be working down a long list
418 ScenePresence s = m_scene.GetScenePresence(p.UUID);
419 if (s != null)
420 {
421 // Also make sure they are actually in the region
422 if (!s.IsChildAgent)
423 {
424 s.ControllingClient.SendTeleportLocationStart();
425 m_scene.TeleportClientHome(s.UUID, s.ControllingClient);
426 }
427 }
428 }
429 }
430 }
431 private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID)
432 {
433 if (TerrainUploader != null)
434 {
435 lock (TerrainUploader)
436 {
437 if (XferID == TerrainUploader.XferID)
438 {
439 remoteClient.OnXferReceive -= TerrainUploader.XferReceive;
440 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
441 TerrainUploader.TerrainUploadDone -= HandleTerrainApplication;
442
443 TerrainUploader = null;
444 remoteClient.SendAlertMessage("Terrain Upload aborted by the client");
445 }
446 }
447 }
448
449 }
450 private void HandleTerrainApplication(string filename, byte[] terrainData, IClientAPI remoteClient)
451 {
452 lock (TerrainUploader)
453 {
454 remoteClient.OnXferReceive -= TerrainUploader.XferReceive;
455 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
456 TerrainUploader.TerrainUploadDone -= HandleTerrainApplication;
457
458 TerrainUploader = null;
459 }
460 remoteClient.SendAlertMessage("Terrain Upload Complete. Loading....");
461 OpenSim.Region.CoreModules.World.Terrain.ITerrainModule terr = m_scene.RequestModuleInterface<OpenSim.Region.CoreModules.World.Terrain.ITerrainModule>();
462
463 if (terr != null)
464 {
465 m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + m_scene.RegionInfo.RegionName);
466 if (System.IO.File.Exists(Util.dataDir() + "/terrain.raw"))
467 {
468 System.IO.File.Delete(Util.dataDir() + "/terrain.raw");
469 }
470 try
471 {
472 System.IO.FileStream input = new System.IO.FileStream(Util.dataDir() + "/terrain.raw", System.IO.FileMode.CreateNew);
473 input.Write(terrainData, 0, terrainData.Length);
474 input.Close();
475 }
476 catch (System.IO.IOException e)
477 {
478 m_log.ErrorFormat("[TERRAIN]: Error Saving a terrain file uploaded via the estate tools. It gave us the following error: {0}", e.ToString());
479 remoteClient.SendAlertMessage("There was an IO Exception loading your terrain. Please check free space");
480
481 return;
482 }
483 catch (System.Security.SecurityException e)
484 {
485 m_log.ErrorFormat("[TERRAIN]: Error Saving a terrain file uploaded via the estate tools. It gave us the following error: {0}", e.ToString());
486 remoteClient.SendAlertMessage("There was a security Exception loading your terrain. Please check the security on the simulator drive");
487
488 return;
489 }
490 catch (System.UnauthorizedAccessException e)
491 {
492 m_log.ErrorFormat("[TERRAIN]: Error Saving a terrain file uploaded via the estate tools. It gave us the following error: {0}", e.ToString());
493 remoteClient.SendAlertMessage("There was a security Exception loading your terrain. Please check the security on the simulator drive");
494
495 return;
496 }
497
498
499
500
501 try
502 {
503 terr.LoadFromFile(Util.dataDir() + "/terrain.raw");
504 remoteClient.SendAlertMessage("Your terrain was loaded. Give it a minute or two to apply");
505 }
506 catch (Exception e)
507 {
508 m_log.ErrorFormat("[TERRAIN]: Error loading a terrain file uploaded via the estate tools. It gave us the following error: {0}", e.ToString());
509 remoteClient.SendAlertMessage("There was a general error loading your terrain. Please fix the terrain file and try again");
510 }
511
512 }
513 else
514 {
515 remoteClient.SendAlertMessage("Unable to apply terrain. Cannot get an instance of the terrain module");
516 }
517
518
519
520 }
521
522 private void handleUploadTerrain(IClientAPI remote_client, string clientFileName)
523 {
524
525 if (TerrainUploader == null)
526 {
527
528 TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName);
529 lock (TerrainUploader)
530 {
531 remote_client.OnXferReceive += TerrainUploader.XferReceive;
532 remote_client.OnAbortXfer += AbortTerrainXferHandler;
533 TerrainUploader.TerrainUploadDone += HandleTerrainApplication;
534 }
535 TerrainUploader.RequestStartXfer(remote_client);
536
537 }
538 else
539 {
540 remote_client.SendAlertMessage("Another Terrain Upload is in progress. Please wait your turn!");
541 }
542
543 }
544 private void handleTerrainRequest(IClientAPI remote_client, string clientFileName)
545 {
546 // Save terrain here
547 OpenSim.Region.CoreModules.World.Terrain.ITerrainModule terr = m_scene.RequestModuleInterface<OpenSim.Region.CoreModules.World.Terrain.ITerrainModule>();
548
549 if (terr != null)
550 {
551 m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + m_scene.RegionInfo.RegionName);
552 if (System.IO.File.Exists(Util.dataDir() + "/terrain.raw"))
553 {
554 System.IO.File.Delete(Util.dataDir() + "/terrain.raw");
555 }
556 terr.SaveToFile(Util.dataDir() + "/terrain.raw");
557
558 System.IO.FileStream input = new System.IO.FileStream(Util.dataDir() + "/terrain.raw", System.IO.FileMode.Open);
559 byte[] bdata = new byte[input.Length];
560 input.Read(bdata, 0, (int)input.Length);
561 remote_client.SendAlertMessage("Terrain file written, starting download...");
562 m_scene.XferManager.AddNewFile("terrain.raw", bdata);
563 // Tell client about it
564 m_log.Warn("[CLIENT]: Sending Terrain to " + remote_client.Name);
565 remote_client.SendInitiateDownload("terrain.raw", clientFileName);
566 }
567 }
568
569 private void HandleRegionInfoRequest(IClientAPI remote_client)
570 {
571 RegionInfoForEstateMenuArgs args = new RegionInfoForEstateMenuArgs();
572 args.billableFactor = m_scene.RegionInfo.EstateSettings.BillableFactor;
573 args.estateID = m_scene.RegionInfo.EstateSettings.EstateID;
574 args.maxAgents = (byte)m_scene.RegionInfo.RegionSettings.AgentLimit;
575 args.objectBonusFactor = (float)m_scene.RegionInfo.RegionSettings.ObjectBonus;
576 args.parentEstateID = m_scene.RegionInfo.EstateSettings.ParentEstateID;
577 args.pricePerMeter = m_scene.RegionInfo.EstateSettings.PricePerMeter;
578 args.redirectGridX = m_scene.RegionInfo.EstateSettings.RedirectGridX;
579 args.redirectGridY = m_scene.RegionInfo.EstateSettings.RedirectGridY;
580 args.regionFlags = GetRegionFlags();
581 byte mature = 13;
582 if (m_scene.RegionInfo.RegionSettings.Maturity == 1)
583 mature = 21;
584 args.simAccess = mature;
585
586 args.sunHour = (float)m_scene.RegionInfo.RegionSettings.SunPosition;
587 args.terrainLowerLimit = (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit;
588 args.terrainRaiseLimit = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit;
589 args.useEstateSun = m_scene.RegionInfo.RegionSettings.UseEstateSun;
590 args.waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
591 args.simName = m_scene.RegionInfo.RegionName;
592
593 remote_client.SendRegionInfoToEstateMenu(args);
594 }
595
596 private void HandleEstateCovenantRequest(IClientAPI remote_client)
597 {
598 remote_client.SendEstateCovenantInformation(m_scene.RegionInfo.RegionSettings.Covenant);
599 }
600
601 private void HandleLandStatRequest(int parcelID, uint reportType, uint requestFlags, string filter, IClientAPI remoteClient)
602 {
603 Dictionary<uint, float> SceneData = new Dictionary<uint,float>();
604 List<UUID> uuidNameLookupList = new List<UUID>();
605
606 if (reportType == 1)
607 {
608 SceneData = m_scene.PhysicsScene.GetTopColliders();
609 }
610 else if (reportType == 0)
611 {
612 SceneData = m_scene.m_sceneGraph.GetTopScripts();
613 }
614
615 List<LandStatReportItem> SceneReport = new List<LandStatReportItem>();
616 lock (SceneData)
617 {
618 foreach (uint obj in SceneData.Keys)
619 {
620 SceneObjectPart prt = m_scene.GetSceneObjectPart(obj);
621 if (prt != null)
622 {
623 if (prt.ParentGroup != null)
624 {
625 SceneObjectGroup sog = prt.ParentGroup;
626 if (sog != null)
627 {
628 LandStatReportItem lsri = new LandStatReportItem();
629 lsri.LocationX = sog.AbsolutePosition.X;
630 lsri.LocationY = sog.AbsolutePosition.Y;
631 lsri.LocationZ = sog.AbsolutePosition.Z;
632 lsri.Score = SceneData[obj];
633 lsri.TaskID = sog.UUID;
634 lsri.TaskLocalID = sog.LocalId;
635 lsri.TaskName = sog.GetPartName(obj);
636 if (m_scene.CommsManager.UUIDNameCachedTest(sog.OwnerID))
637 {
638 lsri.OwnerName = m_scene.CommsManager.UUIDNameRequestString(sog.OwnerID);
639 }
640 else
641 {
642 lsri.OwnerName = "waiting";
643 lock (uuidNameLookupList)
644 uuidNameLookupList.Add(sog.OwnerID);
645 }
646
647 if (filter.Length != 0)
648 {
649 if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter)))
650 {
651 }
652 else
653 {
654 continue;
655 }
656 }
657
658 SceneReport.Add(lsri);
659 }
660 }
661 }
662
663 }
664 }
665 remoteClient.SendLandStatReply(reportType, requestFlags, (uint)SceneReport.Count,SceneReport.ToArray());
666
667 if (uuidNameLookupList.Count > 0)
668 LookupUUID(uuidNameLookupList);
669 }
670
671 private void LookupUUIDSCompleted(IAsyncResult iar)
672 {
673 LookupUUIDS icon = (LookupUUIDS)iar.AsyncState;
674 icon.EndInvoke(iar);
675 }
676 private void LookupUUID(List<UUID> uuidLst)
677 {
678 LookupUUIDS d = LookupUUIDsAsync;
679
680 d.BeginInvoke(uuidLst,
681 LookupUUIDSCompleted,
682 d);
683 }
684 private void LookupUUIDsAsync(List<UUID> uuidLst)
685 {
686 UUID[] uuidarr = new UUID[0];
687
688 lock (uuidLst)
689 {
690 uuidarr = uuidLst.ToArray();
691 }
692
693 for (int i = 0; i < uuidarr.Length; i++)
694 {
695 // string lookupname = m_scene.CommsManager.UUIDNameRequestString(uuidarr[i]);
696 m_scene.CommsManager.UUIDNameRequestString(uuidarr[i]);
697 // we drop it. It gets cached though... so we're ready for the next request.
698 }
699 }
700 #endregion
701
702 #region Outgoing Packets
703
704 public void sendRegionInfoPacketToAll()
705 {
706 List<ScenePresence> avatars = m_scene.GetAvatars();
707
708 for (int i = 0; i < avatars.Count; i++)
709 {
710 HandleRegionInfoRequest(avatars[i].ControllingClient); ;
711 }
712 }
713
714 public void sendRegionHandshake(IClientAPI remoteClient)
715 {
716 RegionHandshakeArgs args = new RegionHandshakeArgs();
717
718 args.isEstateManager = m_scene.RegionInfo.EstateSettings.IsEstateManager(remoteClient.AgentId);
719 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero && m_scene.RegionInfo.EstateSettings.EstateOwner == remoteClient.AgentId)
720 args.isEstateManager = true;
721
722 args.billableFactor = m_scene.RegionInfo.EstateSettings.BillableFactor;
723 args.terrainStartHeight0 = (float)m_scene.RegionInfo.RegionSettings.Elevation1SW;
724 args.terrainHeightRange0 = (float)m_scene.RegionInfo.RegionSettings.Elevation2SW;
725 args.terrainStartHeight1 = (float)m_scene.RegionInfo.RegionSettings.Elevation1NW;
726 args.terrainHeightRange1 = (float)m_scene.RegionInfo.RegionSettings.Elevation2NW;
727 args.terrainStartHeight2 = (float)m_scene.RegionInfo.RegionSettings.Elevation1SE;
728 args.terrainHeightRange2 = (float)m_scene.RegionInfo.RegionSettings.Elevation2SE;
729 args.terrainStartHeight3 = (float)m_scene.RegionInfo.RegionSettings.Elevation1NE;
730 args.terrainHeightRange3 = (float)m_scene.RegionInfo.RegionSettings.Elevation2NE;
731 byte mature = 13;
732 if (m_scene.RegionInfo.RegionSettings.Maturity == 1)
733 mature = 21;
734 args.simAccess = mature;
735 args.waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
736
737 args.regionFlags = GetRegionFlags();
738 args.regionName = m_scene.RegionInfo.RegionName;
739 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero)
740 args.SimOwner = m_scene.RegionInfo.EstateSettings.EstateOwner;
741 else
742 args.SimOwner = m_scene.RegionInfo.MasterAvatarAssignedUUID;
743
744 // Fudge estate owner
745 //if (m_scene.Permissions.IsGod(remoteClient.AgentId))
746 // args.SimOwner = remoteClient.AgentId;
747
748 args.terrainBase0 = UUID.Zero;
749 args.terrainBase1 = UUID.Zero;
750 args.terrainBase2 = UUID.Zero;
751 args.terrainBase3 = UUID.Zero;
752 args.terrainDetail0 = m_scene.RegionInfo.RegionSettings.TerrainTexture1;
753 args.terrainDetail1 = m_scene.RegionInfo.RegionSettings.TerrainTexture2;
754 args.terrainDetail2 = m_scene.RegionInfo.RegionSettings.TerrainTexture3;
755 args.terrainDetail3 = m_scene.RegionInfo.RegionSettings.TerrainTexture4;
756
757 remoteClient.SendRegionHandshake(m_scene.RegionInfo,args);
758 }
759
760 public void sendRegionHandshakeToAll()
761 {
762 m_scene.Broadcast(sendRegionHandshake);
763 }
764
765 public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2)
766 {
767 if (parms2 == 0)
768 {
769 m_scene.RegionInfo.EstateSettings.UseGlobalTime = true;
770 m_scene.RegionInfo.EstateSettings.SunPosition = 0.0;
771 }
772 else
773 {
774 m_scene.RegionInfo.EstateSettings.UseGlobalTime = false;
775 m_scene.RegionInfo.EstateSettings.SunPosition = (double)(parms2 - 0x1800)/1024.0;
776 }
777
778 if ((parms1 & 0x00000010) != 0)
779 m_scene.RegionInfo.EstateSettings.FixedSun = true;
780 else
781 m_scene.RegionInfo.EstateSettings.FixedSun = false;
782
783 if ((parms1 & 0x00008000) != 0)
784 m_scene.RegionInfo.EstateSettings.PublicAccess = true;
785 else
786 m_scene.RegionInfo.EstateSettings.PublicAccess = false;
787
788 if ((parms1 & 0x10000000) != 0)
789 m_scene.RegionInfo.EstateSettings.AllowVoice = true;
790 else
791 m_scene.RegionInfo.EstateSettings.AllowVoice = false;
792
793 if ((parms1 & 0x00100000) != 0)
794 m_scene.RegionInfo.EstateSettings.AllowDirectTeleport = true;
795 else
796 m_scene.RegionInfo.EstateSettings.AllowDirectTeleport = false;
797
798 if ((parms1 & 0x00800000) != 0)
799 m_scene.RegionInfo.EstateSettings.DenyAnonymous = true;
800 else
801 m_scene.RegionInfo.EstateSettings.DenyAnonymous = false;
802
803 if ((parms1 & 0x01000000) != 0)
804 m_scene.RegionInfo.EstateSettings.DenyIdentified = true;
805 else
806 m_scene.RegionInfo.EstateSettings.DenyIdentified = false;
807
808 if ((parms1 & 0x02000000) != 0)
809 m_scene.RegionInfo.EstateSettings.DenyTransacted = true;
810 else
811 m_scene.RegionInfo.EstateSettings.DenyTransacted = false;
812
813 if ((parms1 & 0x40000000) != 0)
814 m_scene.RegionInfo.EstateSettings.DenyMinors = true;
815 else
816 m_scene.RegionInfo.EstateSettings.DenyMinors = false;
817
818 m_scene.RegionInfo.EstateSettings.Save();
819
820 float sun = (float)m_scene.RegionInfo.RegionSettings.SunPosition;
821 if (m_scene.RegionInfo.RegionSettings.UseEstateSun)
822 {
823 sun = (float)m_scene.RegionInfo.EstateSettings.SunPosition;
824 if (m_scene.RegionInfo.EstateSettings.UseGlobalTime)
825 sun = m_scene.EventManager.GetSunLindenHour();
826 }
827
828 m_scene.EventManager.TriggerEstateToolsTimeUpdate(
829 m_scene.RegionInfo.RegionHandle,
830 m_scene.RegionInfo.EstateSettings.FixedSun ||
831 m_scene.RegionInfo.RegionSettings.FixedSun,
832 m_scene.RegionInfo.RegionSettings.UseEstateSun, sun);
833
834 sendDetailedEstateData(remoteClient, invoice);
835 }
836
837 #endregion
838
839 #region IRegionModule Members
840
841 public void Initialise(Scene scene, IConfigSource source)
842 {
843 m_scene = scene;
844 m_scene.RegisterModuleInterface<IEstateModule>(this);
845 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
846 m_scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight;
847 }
848
849
850 public void PostInitialise()
851 {
852 }
853
854 public void Close()
855 {
856 }
857
858 public string Name
859 {
860 get { return "EstateManagementModule"; }
861 }
862
863 public bool IsSharedModule
864 {
865 get { return false; }
866 }
867
868 #endregion
869
870 #region Other Functions
871
872 public void changeWaterHeight(float height)
873 {
874 setRegionTerrainSettings(height,
875 (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit,
876 (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit,
877 m_scene.RegionInfo.RegionSettings.UseEstateSun,
878 m_scene.RegionInfo.RegionSettings.FixedSun,
879 (float)m_scene.RegionInfo.RegionSettings.SunPosition,
880 m_scene.RegionInfo.EstateSettings.UseGlobalTime,
881 m_scene.RegionInfo.EstateSettings.FixedSun,
882 (float)m_scene.RegionInfo.EstateSettings.SunPosition);
883
884 sendRegionInfoPacketToAll();
885 }
886
887 #endregion
888
889 private void EventManager_OnNewClient(IClientAPI client)
890 {
891 client.OnDetailedEstateDataRequest += sendDetailedEstateData;
892 client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler;
893// client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture;
894 client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture;
895 client.OnSetEstateTerrainTextureHeights += setEstateTerrainTextureHeights;
896 client.OnCommitEstateTerrainTextureRequest += handleCommitEstateTerrainTextureRequest;
897 client.OnSetRegionTerrainSettings += setRegionTerrainSettings;
898 client.OnEstateRestartSimRequest += handleEstateRestartSimRequest;
899 client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest;
900 client.OnEstateChangeInfo += handleEstateChangeInfo;
901 client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest;
902 client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage;
903 client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage;
904 client.OnEstateDebugRegionRequest += handleEstateDebugRegionRequest;
905 client.OnEstateTeleportOneUserHomeRequest += handleEstateTeleportOneUserHomeRequest;
906 client.OnEstateTeleportAllUsersHomeRequest += handleEstateTeleportAllUsersHomeRequest;
907 client.OnRequestTerrain += handleTerrainRequest;
908 client.OnUploadTerrain += handleUploadTerrain;
909
910 client.OnRegionInfoRequest += HandleRegionInfoRequest;
911 client.OnEstateCovenantRequest += HandleEstateCovenantRequest;
912 client.OnLandStatRequest += HandleLandStatRequest;
913 sendRegionHandshake(client);
914 }
915
916 public uint GetRegionFlags()
917 {
918 RegionFlags flags = RegionFlags.None;
919
920 // Fully implemented
921 //
922 if (m_scene.RegionInfo.RegionSettings.AllowDamage)
923 flags |= RegionFlags.AllowDamage;
924 if (m_scene.RegionInfo.RegionSettings.BlockTerraform)
925 flags |= RegionFlags.BlockTerraform;
926 if (!m_scene.RegionInfo.RegionSettings.AllowLandResell)
927 flags |= RegionFlags.BlockLandResell;
928 if (m_scene.RegionInfo.RegionSettings.DisableCollisions)
929 flags |= RegionFlags.SkipCollisions;
930 if (m_scene.RegionInfo.RegionSettings.DisableScripts)
931 flags |= RegionFlags.SkipScripts;
932 if (m_scene.RegionInfo.RegionSettings.DisablePhysics)
933 flags |= RegionFlags.SkipPhysics;
934 if (m_scene.RegionInfo.RegionSettings.BlockFly)
935 flags |= RegionFlags.NoFly;
936 if (m_scene.RegionInfo.RegionSettings.RestrictPushing)
937 flags |= RegionFlags.RestrictPushObject;
938 if (m_scene.RegionInfo.RegionSettings.AllowLandJoinDivide)
939 flags |= RegionFlags.AllowParcelChanges;
940 if (m_scene.RegionInfo.RegionSettings.BlockShowInSearch)
941 flags |= (RegionFlags)(1 << 29);
942
943 if (m_scene.RegionInfo.RegionSettings.FixedSun)
944 flags |= RegionFlags.SunFixed;
945 if (m_scene.RegionInfo.RegionSettings.Sandbox)
946 flags |= RegionFlags.Sandbox;
947
948 // Fudge these to always on, so the menu options activate
949 //
950 flags |= RegionFlags.AllowLandmark;
951 flags |= RegionFlags.AllowSetHome;
952
953 // TODO: SkipUpdateInterestList
954
955 // Omitted
956 //
957 // Omitted: NullLayer (what is that?)
958 // Omitted: SkipAgentAction (what does it do?)
959
960 return (uint)flags;
961 }
962
963 public uint GetEstateFlags()
964 {
965 RegionFlags flags = RegionFlags.None;
966
967 if (m_scene.RegionInfo.EstateSettings.FixedSun)
968 flags |= RegionFlags.SunFixed;
969 if (m_scene.RegionInfo.EstateSettings.PublicAccess)
970 flags |= (RegionFlags.PublicAllowed |
971 RegionFlags.ExternallyVisible);
972 if (m_scene.RegionInfo.EstateSettings.AllowVoice)
973 flags |= RegionFlags.AllowVoice;
974 if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport)
975 flags |= RegionFlags.AllowDirectTeleport;
976 if (m_scene.RegionInfo.EstateSettings.DenyAnonymous)
977 flags |= RegionFlags.DenyAnonymous;
978 if (m_scene.RegionInfo.EstateSettings.DenyIdentified)
979 flags |= RegionFlags.DenyIdentified;
980 if (m_scene.RegionInfo.EstateSettings.DenyTransacted)
981 flags |= RegionFlags.DenyTransacted;
982 if (m_scene.RegionInfo.EstateSettings.AbuseEmailToEstateOwner)
983 flags |= RegionFlags.AbuseEmailToEstateOwner;
984 if (m_scene.RegionInfo.EstateSettings.BlockDwell)
985 flags |= RegionFlags.BlockDwell;
986 if (m_scene.RegionInfo.EstateSettings.EstateSkipScripts)
987 flags |= RegionFlags.EstateSkipScripts;
988 if (m_scene.RegionInfo.EstateSettings.ResetHomeOnTeleport)
989 flags |= RegionFlags.ResetHomeOnTeleport;
990 if (m_scene.RegionInfo.EstateSettings.TaxFree)
991 flags |= RegionFlags.TaxFree;
992 if (m_scene.RegionInfo.EstateSettings.DenyMinors)
993 flags |= (RegionFlags)(1 << 30);
994
995 return (uint)flags;
996 }
997
998 public bool IsManager(UUID avatarID)
999 {
1000 if (avatarID == m_scene.RegionInfo.MasterAvatarAssignedUUID)
1001 return true;
1002 if (avatarID == m_scene.RegionInfo.EstateSettings.EstateOwner)
1003 return true;
1004
1005 List<UUID> ems = new List<UUID>(m_scene.RegionInfo.EstateSettings.EstateManagers);
1006 if (ems.Contains(avatarID))
1007 return true;
1008
1009 return false;
1010 }
1011 }
1012}
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
new file mode 100644
index 0000000..94a4072
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
@@ -0,0 +1,127 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using log4net;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications.Cache;
35using OpenSim.Region.Framework.Scenes;
36
37
38namespace OpenSim.Region.CoreModules.World.Estate
39{
40
41 public class EstateTerrainXferHandler
42 {
43 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 private AssetBase m_asset;
46
47 public delegate void TerrainUploadComplete(string name, byte[] filedata, IClientAPI remoteClient);
48
49 public event TerrainUploadComplete TerrainUploadDone;
50
51 //private string m_description = String.Empty;
52 //private string m_name = String.Empty;
53 //private UUID TransactionID = UUID.Zero;
54 private sbyte type = 0;
55
56 public ulong mXferID;
57 private TerrainUploadComplete handlerTerrainUploadDone;
58
59 public EstateTerrainXferHandler(IClientAPI pRemoteClient, string pClientFilename)
60 {
61
62 m_asset = new AssetBase();
63 m_asset.Metadata.FullID = UUID.Zero;
64 m_asset.Metadata.Type = type;
65 m_asset.Data = new byte[0];
66 m_asset.Metadata.Name = pClientFilename;
67 m_asset.Metadata.Description = "empty";
68 m_asset.Metadata.Local = true;
69 m_asset.Metadata.Temporary = true;
70
71 }
72
73 public ulong XferID
74 {
75 get { return mXferID; }
76 }
77
78 public void RequestStartXfer(IClientAPI pRemoteClient)
79 {
80 mXferID = Util.GetNextXferID();
81 pRemoteClient.SendXferRequest(mXferID, m_asset.Metadata.Type, m_asset.Metadata.FullID, 0, Utils.StringToBytes(m_asset.Metadata.Name));
82 }
83
84 /// <summary>
85 /// Process transfer data received from the client.
86 /// </summary>
87 /// <param name="xferID"></param>
88 /// <param name="packetID"></param>
89 /// <param name="data"></param>
90 public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data)
91 {
92 if (mXferID == xferID)
93 {
94 if (m_asset.Data.Length > 1)
95 {
96 byte[] destinationArray = new byte[m_asset.Data.Length + data.Length];
97 Array.Copy(m_asset.Data, 0, destinationArray, 0, m_asset.Data.Length);
98 Array.Copy(data, 0, destinationArray, m_asset.Data.Length, data.Length);
99 m_asset.Data = destinationArray;
100 }
101 else
102 {
103 byte[] buffer2 = new byte[data.Length - 4];
104 Array.Copy(data, 4, buffer2, 0, data.Length - 4);
105 m_asset.Data = buffer2;
106 }
107
108 remoteClient.SendConfirmXfer(xferID, packetID);
109
110 if ((packetID & 0x80000000) != 0)
111 {
112 SendCompleteMessage(remoteClient);
113
114 }
115 }
116 }
117
118 public void SendCompleteMessage(IClientAPI remoteClient)
119 {
120 handlerTerrainUploadDone = TerrainUploadDone;
121 if (handlerTerrainUploadDone != null)
122 {
123 handlerTerrainUploadDone(m_asset.Metadata.Name, m_asset.Data, remoteClient);
124 }
125 }
126 }
127}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
new file mode 100644
index 0000000..41163a0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
@@ -0,0 +1,188 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.CoreModules.World.Land
36{
37 public class LandChannel : ILandChannel
38 {
39 #region Constants
40
41 //Land types set with flags in ParcelOverlay.
42 //Only one of these can be used.
43 public const float BAN_LINE_SAFETY_HIEGHT = 100;
44 public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = 128; //Equals 10000000
45 public const byte LAND_FLAG_PROPERTY_BORDER_WEST = 64; //Equals 01000000
46
47 //RequestResults (I think these are right, they seem to work):
48 public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land
49 public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land
50
51 //ParcelSelectObjects
52 public const int LAND_SELECT_OBJECTS_GROUP = 4;
53 public const int LAND_SELECT_OBJECTS_OTHER = 8;
54 public const int LAND_SELECT_OBJECTS_OWNER = 2;
55 public const byte LAND_TYPE_IS_BEING_AUCTIONED = 5; //Equals 00000101
56 public const byte LAND_TYPE_IS_FOR_SALE = 4; //Equals 00000100
57 public const byte LAND_TYPE_OWNED_BY_GROUP = 2; //Equals 00000010
58 public const byte LAND_TYPE_OWNED_BY_OTHER = 1; //Equals 00000001
59 public const byte LAND_TYPE_OWNED_BY_REQUESTER = 3; //Equals 00000011
60 public const byte LAND_TYPE_PUBLIC = 0; //Equals 00000000
61
62 //These are other constants. Yay!
63 public const int START_LAND_LOCAL_ID = 1;
64
65 #endregion
66
67 private readonly Scene m_scene;
68 private readonly LandManagementModule m_landManagementModule;
69
70 public LandChannel(Scene scene, LandManagementModule landManagementMod)
71 {
72 m_scene = scene;
73 m_landManagementModule = landManagementMod;
74 }
75
76 #region ILandChannel Members
77
78
79 /// <summary>
80 /// Get the land object at the specified point
81 /// </summary>
82 /// <param name="x_float">Value between 0 - 256 on the x axis of the point</param>
83 /// <param name="y_float">Value between 0 - 256 on the y axis of the point</param>
84 /// <returns>Land object at the point supplied</returns>
85 public ILandObject GetLandObject(float x_float, float y_float)
86 {
87 if (m_landManagementModule != null)
88 {
89 return m_landManagementModule.GetLandObject(x_float, y_float);
90 }
91 ILandObject obj = new LandObject(UUID.Zero, false, m_scene);
92 obj.landData.Name = "NO LAND";
93 return obj;
94 }
95
96 public ILandObject GetLandObject(int x, int y)
97 {
98 if (m_landManagementModule != null)
99 {
100 return m_landManagementModule.GetLandObject(x, y);
101 }
102 ILandObject obj = new LandObject(UUID.Zero, false, m_scene);
103 obj.landData.Name = "NO LAND";
104 return obj;
105 }
106
107 public List<ILandObject> AllParcels()
108 {
109 if (m_landManagementModule != null)
110 {
111 return m_landManagementModule.AllParcels();
112 }
113
114 return new List<ILandObject>();
115 }
116
117 public List<ILandObject> ParcelsNearPoint(Vector3 position)
118 {
119 if (m_landManagementModule != null)
120 {
121 return m_landManagementModule.ParcelsNearPoint(position);
122 }
123
124 return new List<ILandObject>();
125 }
126
127 public bool IsLandPrimCountTainted()
128 {
129 if (m_landManagementModule != null)
130 {
131 return m_landManagementModule.IsLandPrimCountTainted();
132 }
133
134 return false;
135 }
136
137 public bool IsForcefulBansAllowed()
138 {
139 if (m_landManagementModule != null)
140 {
141 return m_landManagementModule.AllowedForcefulBans;
142 }
143
144 return false;
145 }
146
147 public void UpdateLandObject(int localID, LandData data)
148 {
149 if (m_landManagementModule != null)
150 {
151 m_landManagementModule.UpdateLandObject(localID, data);
152 }
153 }
154 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
155 {
156 if (m_landManagementModule != null)
157 {
158 m_landManagementModule.ReturnObjectsInParcel(localID, returnType, agentIDs, taskIDs, remoteClient);
159 }
160 }
161
162 public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
163 {
164 if (m_landManagementModule != null)
165 {
166 m_landManagementModule.setParcelObjectMaxOverride(overrideDel);
167 }
168 }
169
170 public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
171 {
172 if (m_landManagementModule != null)
173 {
174 m_landManagementModule.setSimulatorObjectMaxOverride(overrideDel);
175 }
176 }
177
178 public void SetParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
179 {
180 if (m_landManagementModule != null)
181 {
182 m_landManagementModule.setParcelOtherCleanTime(remoteClient, localID, otherCleanTime);
183 }
184 }
185
186 #endregion
187 }
188}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
new file mode 100644
index 0000000..6ae6576
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -0,0 +1,1347 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using OpenMetaverse;
33using log4net;
34using Nini.Config;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Framework;
38using OpenSim.Framework.Servers;
39using OpenSim.Framework.Communications.Capabilities;
40using OpenSim.Region.Physics.Manager;
41using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
42
43namespace OpenSim.Region.CoreModules.World.Land
44{
45 // used for caching
46 internal class ExtendedLandData {
47 public LandData landData;
48 public ulong regionHandle;
49 public uint x, y;
50 }
51
52 public class LandManagementModule : IRegionModule
53 {
54 private static readonly ILog m_log =
55 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private static readonly string remoteParcelRequestPath = "0009/";
58
59 private LandChannel landChannel;
60 private Scene m_scene;
61
62 private readonly int[,] m_landIDList = new int[64, 64];
63 private readonly Dictionary<int, ILandObject> m_landList = new Dictionary<int, ILandObject>();
64
65 private bool m_landPrimCountTainted;
66 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
67
68 private bool m_allowedForcefulBans = true;
69
70 // caches ExtendedLandData
71 private Cache parcelInfoCache;
72
73 #region IRegionModule Members
74
75 public void Initialise(Scene scene, IConfigSource source)
76 {
77 m_scene = scene;
78 m_landIDList.Initialize();
79 landChannel = new LandChannel(scene, this);
80
81 parcelInfoCache = new Cache();
82 parcelInfoCache.Size = 30; // the number of different parcel requests in this region to cache
83 parcelInfoCache.DefaultTTL = new TimeSpan(0, 5, 0);
84
85 m_scene.EventManager.OnParcelPrimCountAdd += AddPrimToLandPrimCounts;
86 m_scene.EventManager.OnParcelPrimCountUpdate += UpdateLandPrimCounts;
87 m_scene.EventManager.OnAvatarEnteringNewParcel += new EventManager.AvatarEnteringNewParcel(handleAvatarChangingParcel);
88 m_scene.EventManager.OnClientMovement += new EventManager.ClientMovement(handleAnyClientMovement);
89 m_scene.EventManager.OnValidateLandBuy += handleLandValidationRequest;
90 m_scene.EventManager.OnLandBuy += handleLandBuyRequest;
91 m_scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
92 m_scene.EventManager.OnSignificantClientMovement += handleSignificantClientMovement;
93 m_scene.EventManager.OnObjectBeingRemovedFromScene += RemovePrimFromLandPrimCounts;
94
95 m_scene.EventManager.OnNoticeNoLandDataFromStorage += this.NoLandDataFromStorage;
96 m_scene.EventManager.OnIncomingLandDataFromStorage += this.IncomingLandObjectsFromStorage;
97 m_scene.EventManager.OnSetAllowForcefulBan += this.SetAllowedForcefulBans;
98 m_scene.EventManager.OnRequestParcelPrimCountUpdate += this.PerformParcelPrimCountUpdate;
99 m_scene.EventManager.OnParcelPrimCountTainted += this.SetPrimsTainted;
100 m_scene.EventManager.OnRegisterCaps += this.OnRegisterCaps;
101
102 lock (m_scene)
103 {
104 m_scene.LandChannel = (ILandChannel) landChannel;
105 }
106 }
107
108 void EventManager_OnNewClient(IClientAPI client)
109 {
110 //Register some client events
111 client.OnParcelPropertiesRequest += new ParcelPropertiesRequest(handleParcelPropertiesRequest);
112 client.OnParcelDivideRequest += new ParcelDivideRequest(handleParcelDivideRequest);
113 client.OnParcelJoinRequest += new ParcelJoinRequest(handleParcelJoinRequest);
114 client.OnParcelPropertiesUpdateRequest += new ParcelPropertiesUpdateRequest(handleParcelPropertiesUpdateRequest);
115 client.OnParcelSelectObjects += new ParcelSelectObjects(handleParcelSelectObjectsRequest);
116 client.OnParcelObjectOwnerRequest += new ParcelObjectOwnerRequest(handleParcelObjectOwnersRequest);
117 client.OnParcelAccessListRequest += new ParcelAccessListRequest(handleParcelAccessRequest);
118 client.OnParcelAccessListUpdateRequest += new ParcelAccessListUpdateRequest(handleParcelAccessUpdateRequest);
119 client.OnParcelAbandonRequest += new ParcelAbandonRequest(handleParcelAbandonRequest);
120 client.OnParcelGodForceOwner += new ParcelGodForceOwner(handleParcelGodForceOwner);
121 client.OnParcelReclaim += new ParcelReclaim(handleParcelReclaim);
122 client.OnParcelInfoRequest += new ParcelInfoRequest(handleParcelInfo);
123 client.OnParcelDwellRequest += new ParcelDwellRequest(handleParcelDwell);
124 if (m_scene.Entities.ContainsKey(client.AgentId))
125 {
126 SendLandUpdate((ScenePresence)m_scene.Entities[client.AgentId], true);
127 SendParcelOverlay(client);
128 }
129 }
130
131 public void PostInitialise()
132 {
133 }
134
135 public void Close()
136 {
137 }
138
139 public string Name
140 {
141 get { return "LandManagementModule"; }
142 }
143
144 public bool IsSharedModule
145 {
146 get { return false; }
147 }
148
149 #endregion
150
151 #region Parcel Add/Remove/Get/Create
152
153 public void SetAllowedForcefulBans(bool forceful)
154 {
155 AllowedForcefulBans = forceful;
156 }
157
158 public void UpdateLandObject(int local_id, LandData data)
159 {
160 LandData newData = data.Copy();
161 newData.LocalID = local_id;
162
163 lock (m_landList)
164 {
165 if (m_landList.ContainsKey(local_id))
166 {
167 m_landList[local_id].landData = newData;
168 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, m_landList[local_id]);
169 }
170 }
171 }
172
173 public bool AllowedForcefulBans
174 {
175 get { return m_allowedForcefulBans; }
176 set { m_allowedForcefulBans = value; }
177 }
178
179 /// <summary>
180 /// Resets the sim to the default land object (full sim piece of land owned by the default user)
181 /// </summary>
182 public void ResetSimLandObjects()
183 {
184 //Remove all the land objects in the sim and add a blank, full sim land object set to public
185 lock (m_landList)
186 {
187 m_landList.Clear();
188 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
189 m_landIDList.Initialize();
190 }
191
192 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
193
194 fullSimParcel.setLandBitmap(fullSimParcel.getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
195 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero)
196 fullSimParcel.landData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
197 else
198 fullSimParcel.landData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID;
199 fullSimParcel.landData.ClaimDate = Util.UnixTimeSinceEpoch();
200 AddLandObject(fullSimParcel);
201 }
202
203 public List<ILandObject> AllParcels()
204 {
205 lock (m_landList)
206 {
207 return new List<ILandObject>(m_landList.Values);
208 }
209 }
210
211 public List<ILandObject> ParcelsNearPoint(Vector3 position)
212 {
213 List<ILandObject> parcelsNear = new List<ILandObject>();
214 for (int x = -4; x <= 4; x += 4)
215 {
216 for (int y = -4; y <= 4; y += 4)
217 {
218 ILandObject check = GetLandObject(position.X + x, position.Y + y);
219 if (check != null)
220 {
221 if (!parcelsNear.Contains(check))
222 {
223 parcelsNear.Add(check);
224 }
225 }
226 }
227 }
228
229 return parcelsNear;
230 }
231
232 public void SendYouAreBannedNotice(ScenePresence avatar)
233 {
234 if (AllowedForcefulBans)
235 {
236 avatar.ControllingClient.SendAlertMessage(
237 "You are not allowed on this parcel because you are banned. Please go away.");
238
239 avatar.PhysicsActor.Position =
240 new PhysicsVector(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y,
241 avatar.lastKnownAllowedPosition.Z);
242 avatar.PhysicsActor.Velocity = new PhysicsVector(0, 0, 0);
243 }
244 else
245 {
246 avatar.ControllingClient.SendAlertMessage(
247 "You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim!");
248 }
249 }
250
251 public void handleAvatarChangingParcel(ScenePresence avatar, int localLandID, UUID regionID)
252 {
253 if (m_scene.RegionInfo.RegionID == regionID)
254 {
255 ILandObject parcelAvatarIsEntering;
256 lock (m_landList)
257 {
258 parcelAvatarIsEntering = m_landList[localLandID];
259 }
260
261 if (parcelAvatarIsEntering != null)
262 {
263 if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT)
264 {
265 if (parcelAvatarIsEntering.isBannedFromLand(avatar.UUID))
266 {
267 SendYouAreBannedNotice(avatar);
268 }
269 else if (parcelAvatarIsEntering.isRestrictedFromLand(avatar.UUID))
270 {
271 avatar.ControllingClient.SendAlertMessage(
272 "You are not allowed on this parcel because the land owner has restricted access. For now, you can enter, but please respect the land owner's decisions (or he can ban you!).");
273 }
274 else
275 {
276 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
277 }
278 }
279 else
280 {
281 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
282 }
283 }
284 }
285 }
286
287 public void SendOutNearestBanLine(IClientAPI avatar)
288 {
289 List<ScenePresence> avatars = m_scene.GetAvatars();
290 foreach (ScenePresence presence in avatars)
291 {
292 if (presence.UUID == avatar.AgentId)
293 {
294 List<ILandObject> checkLandParcels = ParcelsNearPoint(presence.AbsolutePosition);
295 foreach (ILandObject checkBan in checkLandParcels)
296 {
297 if (checkBan.isBannedFromLand(avatar.AgentId))
298 {
299 checkBan.sendLandProperties((int)ParcelStatus.CollisionBanned, false, (int)ParcelResult.Single, avatar);
300 return; //Only send one
301 }
302 if (checkBan.isRestrictedFromLand(avatar.AgentId))
303 {
304 checkBan.sendLandProperties((int)ParcelStatus.CollisionNotOnAccessList, false, (int)ParcelResult.Single, avatar);
305 return; //Only send one
306 }
307 }
308 return;
309 }
310 }
311 }
312
313 public void SendLandUpdate(ScenePresence avatar, bool force)
314 {
315 ILandObject over = GetLandObject((int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
316 (int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
317
318 if (over != null)
319 {
320 if (force)
321 {
322 if (!avatar.IsChildAgent)
323 {
324 over.sendLandUpdateToClient(avatar.ControllingClient);
325 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.LocalID,
326 m_scene.RegionInfo.RegionID);
327 }
328 }
329
330 if (avatar.currentParcelUUID != over.landData.GlobalID)
331 {
332 if (!avatar.IsChildAgent)
333 {
334 over.sendLandUpdateToClient(avatar.ControllingClient);
335 avatar.currentParcelUUID = over.landData.GlobalID;
336 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.LocalID,
337 m_scene.RegionInfo.RegionID);
338 }
339 }
340 }
341 }
342
343 public void SendLandUpdate(ScenePresence avatar)
344 {
345 SendLandUpdate(avatar, false);
346 }
347
348 public void handleSignificantClientMovement(IClientAPI remote_client)
349 {
350 ScenePresence clientAvatar = m_scene.GetScenePresence(remote_client.AgentId);
351
352 if (clientAvatar != null)
353 {
354 SendLandUpdate(clientAvatar);
355 SendOutNearestBanLine(remote_client);
356 ILandObject parcel = GetLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y);
357 if (parcel != null)
358 {
359 if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT &&
360 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown)
361 {
362 handleAvatarChangingParcel(clientAvatar, parcel.landData.LocalID, m_scene.RegionInfo.RegionID);
363 //They are going below the safety line!
364 if (!parcel.isBannedFromLand(clientAvatar.UUID))
365 {
366 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false;
367 }
368 }
369 else if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT &&
370 parcel.isBannedFromLand(clientAvatar.UUID))
371 {
372 SendYouAreBannedNotice(clientAvatar);
373 }
374 }
375 }
376 }
377
378 public void handleAnyClientMovement(ScenePresence avatar)
379 //Like handleSignificantClientMovement, but called with an AgentUpdate regardless of distance.
380 {
381 ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
382 if (over != null)
383 {
384 if (!over.isBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT)
385 {
386 avatar.lastKnownAllowedPosition =
387 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
388 }
389 }
390 }
391
392
393 public void handleParcelAccessRequest(UUID agentID, UUID sessionID, uint flags, int sequenceID,
394 int landLocalID, IClientAPI remote_client)
395 {
396 ILandObject land;
397 lock (m_landList)
398 {
399 m_landList.TryGetValue(landLocalID, out land);
400 }
401
402 if (land != null)
403 {
404 m_landList[landLocalID].sendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
405 }
406 }
407
408 public void handleParcelAccessUpdateRequest(UUID agentID, UUID sessionID, uint flags, int landLocalID,
409 List<ParcelManager.ParcelAccessEntry> entries,
410 IClientAPI remote_client)
411 {
412 ILandObject land;
413 lock (m_landList)
414 {
415 m_landList.TryGetValue(landLocalID, out land);
416 }
417
418 if (land != null)
419 {
420 if (agentID == land.landData.OwnerID)
421 {
422 land.updateAccessList(flags, entries, remote_client);
423 }
424 }
425 else
426 {
427 m_log.WarnFormat("[LAND]: Invalid local land ID {0}", landLocalID);
428 }
429 }
430
431 /// <summary>
432 /// Creates a basic Parcel object without an owner (a zeroed key)
433 /// </summary>
434 /// <returns></returns>
435 public ILandObject CreateBaseLand()
436 {
437 return new LandObject(UUID.Zero, false, m_scene);
438 }
439
440 /// <summary>
441 /// Adds a land object to the stored list and adds them to the landIDList to what they own
442 /// </summary>
443 /// <param name="new_land">The land object being added</param>
444 public ILandObject AddLandObject(ILandObject land)
445 {
446 ILandObject new_land = land.Copy();
447
448 lock (m_landList)
449 {
450 int newLandLocalID = ++m_lastLandLocalID;
451 new_land.landData.LocalID = newLandLocalID;
452
453 bool[,] landBitmap = new_land.getLandBitmap();
454 for (int x = 0; x < 64; x++)
455 {
456 for (int y = 0; y < 64; y++)
457 {
458 if (landBitmap[x, y])
459 {
460 m_landIDList[x, y] = newLandLocalID;
461 }
462 }
463 }
464
465 m_landList.Add(newLandLocalID, new_land);
466 }
467
468 new_land.forceUpdateLandInfo();
469 m_scene.EventManager.TriggerLandObjectAdded(new_land);
470 return new_land;
471 }
472
473 /// <summary>
474 /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
475 /// </summary>
476 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
477 public void removeLandObject(int local_id)
478 {
479 lock (m_landList)
480 {
481 for (int x = 0; x < 64; x++)
482 {
483 for (int y = 0; y < 64; y++)
484 {
485 if (m_landIDList[x, y] == local_id)
486 {
487 m_log.WarnFormat("[LAND]: Not removing land object {0}; still being used at {1}, {2}",
488 local_id, x, y);
489 return;
490 //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
491 }
492 }
493 }
494
495 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[local_id].landData.GlobalID);
496 m_landList.Remove(local_id);
497 }
498 }
499
500 private void performFinalLandJoin(ILandObject master, ILandObject slave)
501 {
502 bool[,] landBitmapSlave = slave.getLandBitmap();
503 lock (m_landList)
504 {
505 for (int x = 0; x < 64; x++)
506 {
507 for (int y = 0; y < 64; y++)
508 {
509 if (landBitmapSlave[x, y])
510 {
511 m_landIDList[x, y] = master.landData.LocalID;
512 }
513 }
514 }
515 }
516
517 removeLandObject(slave.landData.LocalID);
518 UpdateLandObject(master.landData.LocalID, master.landData);
519 }
520
521 public ILandObject GetLandObject(int parcelLocalID)
522 {
523 lock (m_landList)
524 {
525 if (m_landList.ContainsKey(parcelLocalID))
526 {
527 return m_landList[parcelLocalID];
528 }
529 }
530 return null;
531 }
532
533 /// <summary>
534 /// Get the land object at the specified point
535 /// </summary>
536 /// <param name="x_float">Value between 0 - 256 on the x axis of the point</param>
537 /// <param name="y_float">Value between 0 - 256 on the y axis of the point</param>
538 /// <returns>Land object at the point supplied</returns>
539 public ILandObject GetLandObject(float x_float, float y_float)
540 {
541 int x;
542 int y;
543
544 try
545 {
546 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0));
547 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0));
548 }
549 catch (OverflowException)
550 {
551 return null;
552 }
553
554 if (x >= 64 || y >= 64 || x < 0 || y < 0)
555 {
556 return null;
557 }
558 lock (m_landList)
559 {
560 // Corner case. If an autoreturn happens during sim startup
561 // we will come here with the list uninitialized
562 //
563 if (m_landList.ContainsKey(m_landIDList[x, y]))
564 return m_landList[m_landIDList[x, y]];
565 return null;
566 }
567 }
568
569 public ILandObject GetLandObject(int x, int y)
570 {
571 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0)
572 {
573 // These exceptions here will cause a lot of complaints from the users specifically because
574 // they happen every time at border crossings
575 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
576 }
577 lock (m_landIDList)
578 {
579 return m_landList[m_landIDList[x / 4, y / 4]];
580 }
581 }
582
583 #endregion
584
585 #region Parcel Modification
586
587 public void ResetAllLandPrimCounts()
588 {
589 lock (m_landList)
590 {
591 foreach (LandObject p in m_landList.Values)
592 {
593 p.resetLandPrimCounts();
594 }
595 }
596 }
597
598 public void SetPrimsTainted()
599 {
600 m_landPrimCountTainted = true;
601 }
602
603 public bool IsLandPrimCountTainted()
604 {
605 return m_landPrimCountTainted;
606 }
607
608 public void AddPrimToLandPrimCounts(SceneObjectGroup obj)
609 {
610 Vector3 position = obj.AbsolutePosition;
611 ILandObject landUnderPrim = GetLandObject(position.X, position.Y);
612 if (landUnderPrim != null)
613 {
614 landUnderPrim.addPrimToCount(obj);
615 }
616 }
617
618 public void RemovePrimFromLandPrimCounts(SceneObjectGroup obj)
619 {
620
621 lock (m_landList)
622 {
623 foreach (LandObject p in m_landList.Values)
624 {
625 p.removePrimFromCount(obj);
626 }
627 }
628 }
629
630 public void FinalizeLandPrimCountUpdate()
631 {
632 //Get Simwide prim count for owner
633 Dictionary<UUID, List<LandObject>> landOwnersAndParcels = new Dictionary<UUID, List<LandObject>>();
634 lock (m_landList)
635 {
636 foreach (LandObject p in m_landList.Values)
637 {
638 if (!landOwnersAndParcels.ContainsKey(p.landData.OwnerID))
639 {
640 List<LandObject> tempList = new List<LandObject>();
641 tempList.Add(p);
642 landOwnersAndParcels.Add(p.landData.OwnerID, tempList);
643 }
644 else
645 {
646 landOwnersAndParcels[p.landData.OwnerID].Add(p);
647 }
648 }
649 }
650
651 foreach (UUID owner in landOwnersAndParcels.Keys)
652 {
653 int simArea = 0;
654 int simPrims = 0;
655 foreach (LandObject p in landOwnersAndParcels[owner])
656 {
657 simArea += p.landData.Area;
658 simPrims += p.landData.OwnerPrims + p.landData.OtherPrims + p.landData.GroupPrims +
659 p.landData.SelectedPrims;
660 }
661
662 foreach (LandObject p in landOwnersAndParcels[owner])
663 {
664 p.landData.SimwideArea = simArea;
665 p.landData.SimwidePrims = simPrims;
666 }
667 }
668 }
669
670 public void UpdateLandPrimCounts()
671 {
672 ResetAllLandPrimCounts();
673 foreach (EntityBase obj in m_scene.Entities)
674 {
675 if (obj != null)
676 {
677 if ((obj is SceneObjectGroup) && !obj.IsDeleted && !((SceneObjectGroup) obj).IsAttachment)
678 {
679 m_scene.EventManager.TriggerParcelPrimCountAdd((SceneObjectGroup) obj);
680 }
681 }
682 }
683 FinalizeLandPrimCountUpdate();
684 m_landPrimCountTainted = false;
685 }
686
687 public void PerformParcelPrimCountUpdate()
688 {
689 ResetAllLandPrimCounts();
690 m_scene.EventManager.TriggerParcelPrimCountUpdate();
691 FinalizeLandPrimCountUpdate();
692 m_landPrimCountTainted = false;
693 }
694
695 /// <summary>
696 /// Subdivides a piece of land
697 /// </summary>
698 /// <param name="start_x">West Point</param>
699 /// <param name="start_y">South Point</param>
700 /// <param name="end_x">East Point</param>
701 /// <param name="end_y">North Point</param>
702 /// <param name="attempting_user_id">UUID of user who is trying to subdivide</param>
703 /// <returns>Returns true if successful</returns>
704 private void subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
705 {
706 //First, lets loop through the points and make sure they are all in the same peice of land
707 //Get the land object at start
708
709 ILandObject startLandObject = GetLandObject(start_x, start_y);
710
711 if (startLandObject == null) return;
712
713 //Loop through the points
714 try
715 {
716 int totalX = end_x - start_x;
717 int totalY = end_y - start_y;
718 for (int y = 0; y < totalY; y++)
719 {
720 for (int x = 0; x < totalX; x++)
721 {
722 ILandObject tempLandObject = GetLandObject(start_x + x, start_y + y);
723 if (tempLandObject == null) return;
724 if (tempLandObject != startLandObject) return;
725 }
726 }
727 }
728 catch (Exception)
729 {
730 return;
731 }
732
733 //If we are still here, then they are subdividing within one piece of land
734 //Check owner
735 if (!m_scene.Permissions.CanEditParcel(attempting_user_id, startLandObject))
736 {
737 return;
738 }
739
740 //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
741 ILandObject newLand = startLandObject.Copy();
742 newLand.landData.Name = "Subdivision of " + newLand.landData.Name;
743 newLand.landData.GlobalID = UUID.Random();
744
745 newLand.setLandBitmap(newLand.getSquareLandBitmap(start_x, start_y, end_x, end_y));
746
747 //Now, lets set the subdivision area of the original to false
748 int startLandObjectIndex = startLandObject.landData.LocalID;
749 lock (m_landList)
750 {
751 m_landList[startLandObjectIndex].setLandBitmap(
752 newLand.modifyLandBitmapSquare(startLandObject.getLandBitmap(), start_x, start_y, end_x, end_y, false));
753 m_landList[startLandObjectIndex].forceUpdateLandInfo();
754 }
755
756 SetPrimsTainted();
757
758 //Now add the new land object
759 ILandObject result = AddLandObject(newLand);
760 UpdateLandObject(startLandObject.landData.LocalID, startLandObject.landData);
761 result.sendLandUpdateToAvatarsOverMe();
762 }
763
764 /// <summary>
765 /// Join 2 land objects together
766 /// </summary>
767 /// <param name="start_x">x value in first piece of land</param>
768 /// <param name="start_y">y value in first piece of land</param>
769 /// <param name="end_x">x value in second peice of land</param>
770 /// <param name="end_y">y value in second peice of land</param>
771 /// <param name="attempting_user_id">UUID of the avatar trying to join the land objects</param>
772 /// <returns>Returns true if successful</returns>
773 private void join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
774 {
775 end_x -= 4;
776 end_y -= 4;
777
778 List<ILandObject> selectedLandObjects = new List<ILandObject>();
779 int stepYSelected;
780 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
781 {
782 int stepXSelected;
783 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
784 {
785 ILandObject p = GetLandObject(stepXSelected, stepYSelected);
786
787 if (p != null)
788 {
789 if (!selectedLandObjects.Contains(p))
790 {
791 selectedLandObjects.Add(p);
792 }
793 }
794 }
795 }
796 ILandObject masterLandObject = selectedLandObjects[0];
797 selectedLandObjects.RemoveAt(0);
798
799 if (selectedLandObjects.Count < 1)
800 {
801 return;
802 }
803 if (!m_scene.Permissions.CanEditParcel(attempting_user_id, masterLandObject))
804 {
805 return;
806 }
807 foreach (ILandObject p in selectedLandObjects)
808 {
809 if (p.landData.OwnerID != masterLandObject.landData.OwnerID)
810 {
811 return;
812 }
813 }
814
815 lock (m_landList)
816 {
817 foreach (ILandObject slaveLandObject in selectedLandObjects)
818 {
819 m_landList[masterLandObject.landData.LocalID].setLandBitmap(
820 slaveLandObject.mergeLandBitmaps(masterLandObject.getLandBitmap(), slaveLandObject.getLandBitmap()));
821 performFinalLandJoin(masterLandObject, slaveLandObject);
822 }
823 }
824 SetPrimsTainted();
825
826 masterLandObject.sendLandUpdateToAvatarsOverMe();
827 }
828
829 #endregion
830
831 #region Parcel Updating
832
833 /// <summary>
834 /// Where we send the ParcelOverlay packet to the client
835 /// </summary>
836 /// <param name="remote_client">The object representing the client</param>
837 public void SendParcelOverlay(IClientAPI remote_client)
838 {
839 const int LAND_BLOCKS_PER_PACKET = 1024;
840
841 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
842 int byteArrayCount = 0;
843 int sequenceID = 0;
844
845 for (int y = 0; y < 64; y++)
846 {
847 for (int x = 0; x < 64; x++)
848 {
849 byte tempByte = 0; //This represents the byte for the current 4x4
850
851 ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4);
852
853 if (currentParcelBlock != null)
854 {
855 if (currentParcelBlock.landData.OwnerID == remote_client.AgentId)
856 {
857 //Owner Flag
858 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
859 }
860 else if (currentParcelBlock.landData.SalePrice > 0 &&
861 (currentParcelBlock.landData.AuthBuyerID == UUID.Zero ||
862 currentParcelBlock.landData.AuthBuyerID == remote_client.AgentId))
863 {
864 //Sale Flag
865 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
866 }
867 else if (currentParcelBlock.landData.OwnerID == UUID.Zero)
868 {
869 //Public Flag
870 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
871 }
872 else
873 {
874 //Other Flag
875 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
876 }
877
878 //Now for border control
879
880 ILandObject westParcel = null;
881 ILandObject southParcel = null;
882 if (x > 0)
883 {
884 westParcel = GetLandObject((x - 1) * 4, y * 4);
885 }
886 if (y > 0)
887 {
888 southParcel = GetLandObject(x * 4, (y - 1) * 4);
889 }
890
891 if (x == 0)
892 {
893 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
894 }
895 else if (westParcel != null && westParcel != currentParcelBlock)
896 {
897 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
898 }
899
900 if (y == 0)
901 {
902 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
903 }
904 else if (southParcel != null && southParcel != currentParcelBlock)
905 {
906 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
907 }
908
909 byteArray[byteArrayCount] = tempByte;
910 byteArrayCount++;
911 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
912 {
913 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
914 byteArrayCount = 0;
915 sequenceID++;
916 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
917 }
918 }
919 }
920 }
921 }
922
923 public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
924 bool snap_selection, IClientAPI remote_client)
925 {
926 //Get the land objects within the bounds
927 List<ILandObject> temp = new List<ILandObject>();
928 int inc_x = end_x - start_x;
929 int inc_y = end_y - start_y;
930 for (int x = 0; x < inc_x; x++)
931 {
932 for (int y = 0; y < inc_y; y++)
933 {
934 ILandObject currentParcel = GetLandObject(start_x + x, start_y + y);
935
936 if (currentParcel != null)
937 {
938 if (!temp.Contains(currentParcel))
939 {
940 currentParcel.forceUpdateLandInfo();
941 temp.Add(currentParcel);
942 }
943 }
944 }
945 }
946
947 int requestResult = LandChannel.LAND_RESULT_SINGLE;
948 if (temp.Count > 1)
949 {
950 requestResult = LandChannel.LAND_RESULT_MULTIPLE;
951 }
952
953 for (int i = 0; i < temp.Count; i++)
954 {
955 temp[i].sendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
956 }
957
958 SendParcelOverlay(remote_client);
959 }
960
961 public void handleParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
962 {
963 ILandObject land;
964 lock (m_landList)
965 {
966 m_landList.TryGetValue(localID, out land);
967 }
968
969 if (land != null) land.updateLandProperties(args, remote_client);
970 }
971
972 public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
973 {
974 subdivide(west, south, east, north, remote_client.AgentId);
975 }
976
977 public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
978 {
979 join(west, south, east, north, remote_client.AgentId);
980 }
981
982 public void handleParcelSelectObjectsRequest(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client)
983 {
984 m_landList[local_id].sendForceObjectSelect(local_id, request_type, returnIDs, remote_client);
985 }
986
987 public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client)
988 {
989 ILandObject land;
990 lock (m_landList)
991 {
992 m_landList.TryGetValue(local_id, out land);
993 }
994
995 if (land != null)
996 {
997 m_landList[local_id].sendLandObjectOwners(remote_client);
998 }
999 else
1000 {
1001 m_log.WarnFormat("[PARCEL]: Invalid land object {0} passed for parcel object owner request", local_id);
1002 }
1003 }
1004
1005 public void handleParcelGodForceOwner(int local_id, UUID ownerID, IClientAPI remote_client)
1006 {
1007 ILandObject land;
1008 lock (m_landList)
1009 {
1010 m_landList.TryGetValue(local_id, out land);
1011 }
1012
1013 if (land != null)
1014 {
1015 if (m_scene.Permissions.IsGod(remote_client.AgentId))
1016 {
1017 land.landData.OwnerID = ownerID;
1018
1019 m_scene.Broadcast(SendParcelOverlay);
1020 land.sendLandUpdateToClient(remote_client);
1021 }
1022 }
1023 }
1024
1025 public void handleParcelAbandonRequest(int local_id, IClientAPI remote_client)
1026 {
1027 ILandObject land;
1028 lock (m_landList)
1029 {
1030 m_landList.TryGetValue(local_id, out land);
1031 }
1032
1033 if (land != null)
1034 {
1035 if (m_scene.Permissions.CanAbandonParcel(remote_client.AgentId, land))
1036 {
1037 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero)
1038 land.landData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1039 else
1040 land.landData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID;
1041 m_scene.Broadcast(SendParcelOverlay);
1042 land.sendLandUpdateToClient(remote_client);
1043 }
1044 }
1045 }
1046
1047 public void handleParcelReclaim(int local_id, IClientAPI remote_client)
1048 {
1049 ILandObject land;
1050 lock (m_landList)
1051 {
1052 m_landList.TryGetValue(local_id, out land);
1053 }
1054
1055 if (land != null)
1056 {
1057 if (m_scene.Permissions.CanReclaimParcel(remote_client.AgentId, land))
1058 {
1059 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero)
1060 land.landData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1061 else
1062 land.landData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID;
1063 land.landData.ClaimDate = Util.UnixTimeSinceEpoch();
1064 m_scene.Broadcast(SendParcelOverlay);
1065 land.sendLandUpdateToClient(remote_client);
1066 }
1067 }
1068 }
1069 #endregion
1070
1071 // If the economy has been validated by the economy module,
1072 // and land has been validated as well, this method transfers
1073 // the land ownership
1074
1075 public void handleLandBuyRequest(Object o, EventManager.LandBuyArgs e)
1076 {
1077 if (e.economyValidated && e.landValidated)
1078 {
1079 ILandObject land;
1080 lock (m_landList)
1081 {
1082 m_landList.TryGetValue(e.parcelLocalID, out land);
1083 }
1084
1085 if (land != null)
1086 {
1087 land.updateLandSold(e.agentId, e.groupId, e.groupOwned, (uint)e.transactionID, e.parcelPrice, e.parcelArea);
1088 }
1089 }
1090 }
1091
1092 // After receiving a land buy packet, first the data needs to
1093 // be validated. This method validates the right to buy the
1094 // parcel
1095
1096 public void handleLandValidationRequest(Object o, EventManager.LandBuyArgs e)
1097 {
1098 if (e.landValidated == false)
1099 {
1100 ILandObject lob = null;
1101 lock (m_landList)
1102 {
1103 m_landList.TryGetValue(e.parcelLocalID, out lob);
1104 }
1105
1106 if (lob != null)
1107 {
1108 UUID AuthorizedID = lob.landData.AuthBuyerID;
1109 int saleprice = lob.landData.SalePrice;
1110 UUID pOwnerID = lob.landData.OwnerID;
1111
1112 bool landforsale = ((lob.landData.Flags &
1113 (uint)(Parcel.ParcelFlags.ForSale | Parcel.ParcelFlags.ForSaleObjects | Parcel.ParcelFlags.SellParcelObjects)) != 0);
1114 if ((AuthorizedID == UUID.Zero || AuthorizedID == e.agentId) && e.parcelPrice >= saleprice && landforsale)
1115 {
1116 // TODO I don't think we have to lock it here, no?
1117 //lock (e)
1118 //{
1119 e.parcelOwnerID = pOwnerID;
1120 e.landValidated = true;
1121 //}
1122 }
1123 }
1124 }
1125 }
1126
1127 #region Land Object From Storage Functions
1128
1129 public void IncomingLandObjectsFromStorage(List<LandData> data)
1130 {
1131 for (int i = 0; i < data.Count; i++)
1132 {
1133 IncomingLandObjectFromStorage(data[i]);
1134 }
1135 }
1136
1137 public void IncomingLandObjectFromStorage(LandData data)
1138 {
1139 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene);
1140 new_land.landData = data.Copy();
1141 new_land.setLandBitmapFromByteArray();
1142 AddLandObject(new_land);
1143 }
1144
1145 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
1146 {
1147 ILandObject selectedParcel = null;
1148 lock (m_landList)
1149 {
1150 m_landList.TryGetValue(localID, out selectedParcel);
1151 }
1152
1153 if (selectedParcel == null) return;
1154
1155 selectedParcel.returnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
1156 }
1157
1158 public void NoLandDataFromStorage()
1159 {
1160 ResetSimLandObjects();
1161 }
1162
1163 #endregion
1164
1165 public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
1166 {
1167 lock (m_landList)
1168 {
1169 foreach (LandObject obj in m_landList.Values)
1170 {
1171 obj.setParcelObjectMaxOverride(overrideDel);
1172 }
1173 }
1174 }
1175
1176 public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
1177 {
1178 }
1179
1180 #region CAPS handler
1181
1182 private void OnRegisterCaps(UUID agentID, Caps caps)
1183 {
1184 string capsBase = "/CAPS/" + caps.CapsObjectPath;
1185 caps.RegisterHandler("RemoteParcelRequest",
1186 new RestStreamHandler("POST", capsBase + remoteParcelRequestPath,
1187 delegate(string request, string path, string param,
1188 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
1189 {
1190 return RemoteParcelRequest(request, path, param, agentID, caps);
1191 }));
1192 }
1193
1194 // we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the
1195 // "real" parcelID, because we wouldn't be able to map that to the region the parcel belongs to.
1196 // So, we create a "fake" parcelID by using the regionHandle (64 bit), and the local (integer) x
1197 // and y coordinate (each 8 bit), encoded in a UUID (128 bit).
1198 //
1199 // Request format:
1200 // <llsd>
1201 // <map>
1202 // <key>location</key>
1203 // <array>
1204 // <real>1.23</real>
1205 // <real>45..6</real>
1206 // <real>78.9</real>
1207 // </array>
1208 // <key>region_id</key>
1209 // <uuid>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</uuid>
1210 // </map>
1211 // </llsd>
1212 private string RemoteParcelRequest(string request, string path, string param, UUID agentID, Caps caps)
1213 {
1214 UUID parcelID = UUID.Zero;
1215 try
1216 {
1217 Hashtable hash = new Hashtable();
1218 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
1219 if (hash.ContainsKey("region_id") && hash.ContainsKey("location"))
1220 {
1221 UUID regionID = (UUID)hash["region_id"];
1222 ArrayList list = (ArrayList)hash["location"];
1223 uint x = (uint)(double)list[0];
1224 uint y = (uint)(double)list[1];
1225 if (hash.ContainsKey("region_handle"))
1226 {
1227 // if you do a "About Landmark" on a landmark a second time, the viewer sends the
1228 // region_handle it got earlier via RegionHandleRequest
1229 ulong regionHandle = Util.BytesToUInt64Big((byte[])hash["region_handle"]);
1230 parcelID = Util.BuildFakeParcelID(regionHandle, x, y);
1231 }
1232 else if (regionID == m_scene.RegionInfo.RegionID)
1233 {
1234 // a parcel request for a local parcel => no need to query the grid
1235 parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y);
1236 }
1237 else
1238 {
1239 // a parcel request for a parcel in another region. Ask the grid about the region
1240 RegionInfo info = m_scene.CommsManager.GridService.RequestNeighbourInfo(regionID);
1241 if (info != null)
1242 parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y);
1243 }
1244 }
1245 }
1246 catch (LLSD.LLSDParseException e)
1247 {
1248 m_log.ErrorFormat("[LAND] Fetch error: {0}", e.Message);
1249 m_log.ErrorFormat("[LAND] ... in request {0}", request);
1250 }
1251 catch(InvalidCastException)
1252 {
1253 m_log.ErrorFormat("[LAND] Wrong type in request {0}", request);
1254 }
1255
1256 LLSDRemoteParcelResponse response = new LLSDRemoteParcelResponse();
1257 response.parcel_id = parcelID;
1258 m_log.DebugFormat("[LAND] got parcelID {0}", parcelID);
1259
1260 return LLSDHelpers.SerialiseLLSDReply(response);
1261 }
1262
1263 #endregion
1264
1265 private void handleParcelDwell(int localID, IClientAPI remoteClient)
1266 {
1267 ILandObject selectedParcel = null;
1268 lock (m_landList)
1269 {
1270 if (!m_landList.TryGetValue(localID, out selectedParcel))
1271 return;
1272 }
1273
1274 remoteClient.SendParcelDwellReply(localID, selectedParcel.landData.GlobalID, selectedParcel.landData.Dwell);
1275 }
1276
1277 private void handleParcelInfo(IClientAPI remoteClient, UUID parcelID)
1278 {
1279 if (parcelID == UUID.Zero)
1280 return;
1281
1282 ExtendedLandData data = (ExtendedLandData)parcelInfoCache.Get(parcelID, delegate(UUID parcel) {
1283 // assume we've got the parcelID we just computed in RemoteParcelRequest
1284 ExtendedLandData extLandData = new ExtendedLandData();
1285 Util.ParseFakeParcelID(parcel, out extLandData.regionHandle, out extLandData.x, out extLandData.y);
1286 m_log.DebugFormat("[LAND] got parcelinfo request for regionHandle {0}, x/y {1}/{2}",
1287 extLandData.regionHandle, extLandData.x, extLandData.y);
1288
1289 // for this region or for somewhere else?
1290 if (extLandData.regionHandle == m_scene.RegionInfo.RegionHandle)
1291 {
1292 extLandData.landData = this.GetLandObject(extLandData.x, extLandData.y).landData;
1293 }
1294 else
1295 {
1296 extLandData.landData = m_scene.CommsManager.GridService.RequestLandData(extLandData.regionHandle,
1297 extLandData.x,
1298 extLandData.y);
1299 if (extLandData.landData == null)
1300 {
1301 // we didn't find the region/land => don't cache
1302 return null;
1303 }
1304 }
1305 return extLandData;
1306 });
1307
1308 if (data != null) // if we found some data, send it
1309 {
1310 RegionInfo info;
1311 if (data.regionHandle == m_scene.RegionInfo.RegionHandle)
1312 {
1313 info = m_scene.RegionInfo;
1314 }
1315 else
1316 {
1317 // most likely still cached from building the extLandData entry
1318 info = m_scene.CommsManager.GridService.RequestNeighbourInfo(data.regionHandle);
1319 }
1320 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
1321 m_log.DebugFormat("[LAND] got parcelinfo for parcel {0} in region {1}; sending...",
1322 data.landData.Name, data.regionHandle);
1323 remoteClient.SendParcelInfo(info, data.landData, parcelID, data.x, data.y);
1324 }
1325 else
1326 m_log.Debug("[LAND] got no parcelinfo; not sending");
1327 }
1328
1329 public void setParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
1330 {
1331 ILandObject land;
1332 lock (m_landList)
1333 {
1334 m_landList.TryGetValue(localID, out land);
1335 }
1336
1337 if (land == null) return;
1338
1339 if (!m_scene.Permissions.CanEditParcel(remoteClient.AgentId, land))
1340 return;
1341
1342 land.landData.OtherCleanTime = otherCleanTime;
1343
1344 UpdateLandObject(localID, land.landData);
1345 }
1346 }
1347}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
new file mode 100644
index 0000000..fc5bef1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -0,0 +1,930 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36
37namespace OpenSim.Region.CoreModules.World.Land
38{
39 /// <summary>
40 /// Keeps track of a specific piece of land's information
41 /// </summary>
42 public class LandObject : ILandObject
43 {
44 #region Member Variables
45
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 private bool[,] m_landBitmap = new bool[64,64];
48
49 protected LandData m_landData = new LandData();
50 protected Scene m_scene;
51 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
52
53 public bool[,] landBitmap
54 {
55 get { return m_landBitmap; }
56 set { m_landBitmap = value; }
57 }
58
59 #endregion
60
61 #region ILandObject Members
62
63 public LandData landData
64 {
65 get { return m_landData; }
66
67 set { m_landData = value; }
68 }
69
70 public UUID regionUUID
71 {
72 get { return m_scene.RegionInfo.RegionID; }
73 }
74
75 #region Constructors
76
77 public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
78 {
79 m_scene = scene;
80 landData.OwnerID = owner_id;
81 landData.IsGroupOwned = is_group_owned;
82 }
83
84 #endregion
85
86 #region Member Functions
87
88 #region General Functions
89
90 /// <summary>
91 /// Checks to see if this land object contains a point
92 /// </summary>
93 /// <param name="x"></param>
94 /// <param name="y"></param>
95 /// <returns>Returns true if the piece of land contains the specified point</returns>
96 public bool containsPoint(int x, int y)
97 {
98 if (x >= 0 && y >= 0 && x <= Constants.RegionSize && x <= Constants.RegionSize)
99 {
100 return (landBitmap[x / 4, y / 4] == true);
101 }
102 else
103 {
104 return false;
105 }
106 }
107
108 public ILandObject Copy()
109 {
110 ILandObject newLand = new LandObject(landData.OwnerID, landData.IsGroupOwned, m_scene);
111
112 //Place all new variables here!
113 newLand.landBitmap = (bool[,]) (landBitmap.Clone());
114 newLand.landData = landData.Copy();
115
116 return newLand;
117 }
118
119
120 static overrideParcelMaxPrimCountDelegate overrideParcelMaxPrimCount;
121 static overrideSimulatorMaxPrimCountDelegate overrideSimulatorMaxPrimCount;
122
123 public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
124 {
125 overrideParcelMaxPrimCount = overrideDel;
126 }
127 public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
128 {
129 overrideSimulatorMaxPrimCount = overrideDel;
130 }
131
132 public int getParcelMaxPrimCount(ILandObject thisObject)
133 {
134 if (overrideParcelMaxPrimCount != null)
135 {
136 return overrideParcelMaxPrimCount(thisObject);
137 }
138 else
139 {
140 //Normal Calculations
141 return Convert.ToInt32(
142 Math.Round((Convert.ToDecimal(landData.Area) / Convert.ToDecimal(65536)) * m_scene.objectCapacity *
143 Convert.ToDecimal(m_scene.RegionInfo.RegionSettings.ObjectBonus))); ;
144 }
145 }
146 public int getSimulatorMaxPrimCount(ILandObject thisObject)
147 {
148 if (overrideSimulatorMaxPrimCount != null)
149 {
150 return overrideSimulatorMaxPrimCount(thisObject);
151 }
152 else
153 {
154 //Normal Calculations
155 return m_scene.objectCapacity;
156 }
157 }
158 #endregion
159
160 #region Packet Request Handling
161
162 public void sendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
163 {
164 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
165 uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
166 if (estateModule != null)
167 regionFlags = estateModule.GetRegionFlags();
168
169 // In a perfect world, this would have worked.
170 //
171// if ((landData.Flags & (uint)Parcel.ParcelFlags.AllowLandmark) != 0)
172// regionFlags |= (uint)RegionFlags.AllowLandmark;
173// if (landData.OwnerID == remote_client.AgentId)
174// regionFlags |= (uint)RegionFlags.AllowSetHome;
175 remote_client.SendLandProperties(sequence_id,
176 snap_selection, request_result, landData,
177 (float)m_scene.RegionInfo.RegionSettings.ObjectBonus,
178 getParcelMaxPrimCount(this),
179 getSimulatorMaxPrimCount(this), regionFlags);
180 }
181
182 public void updateLandProperties(LandUpdateArgs args, IClientAPI remote_client)
183 {
184 if (m_scene.Permissions.CanEditParcel(remote_client.AgentId,this))
185 {
186 //Needs later group support
187 LandData newData = landData.Copy();
188
189 if (args.AuthBuyerID != newData.AuthBuyerID || args.SalePrice != newData.SalePrice)
190 {
191 if (m_scene.Permissions.CanSellParcel(remote_client.AgentId, this))
192 {
193 newData.AuthBuyerID = args.AuthBuyerID;
194 newData.SalePrice = args.SalePrice;
195 }
196 }
197 newData.Category = args.Category;
198 newData.Description = args.Desc;
199 newData.GroupID = args.GroupID;
200 newData.LandingType = args.LandingType;
201 newData.MediaAutoScale = args.MediaAutoScale;
202 newData.MediaID = args.MediaID;
203 newData.MediaURL = args.MediaURL;
204 newData.MusicURL = args.MusicURL;
205 newData.Name = args.Name;
206 newData.Flags = args.ParcelFlags;
207 newData.PassHours = args.PassHours;
208 newData.PassPrice = args.PassPrice;
209 newData.SnapshotID = args.SnapshotID;
210 newData.UserLocation = args.UserLocation;
211 newData.UserLookAt = args.UserLookAt;
212
213 m_scene.LandChannel.UpdateLandObject(landData.LocalID, newData);
214
215 sendLandUpdateToAvatarsOverMe();
216 }
217 }
218
219 public void updateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
220 {
221 LandData newData = landData.Copy();
222 newData.OwnerID = avatarID;
223 newData.GroupID = groupID;
224 newData.IsGroupOwned = groupOwned;
225 //newData.auctionID = AuctionID;
226 newData.ClaimDate = Util.UnixTimeSinceEpoch();
227 newData.ClaimPrice = claimprice;
228 newData.SalePrice = 0;
229 newData.AuthBuyerID = UUID.Zero;
230 newData.Flags &= ~(uint) (Parcel.ParcelFlags.ForSale | Parcel.ParcelFlags.ForSaleObjects | Parcel.ParcelFlags.SellParcelObjects);
231 m_scene.LandChannel.UpdateLandObject(landData.LocalID, newData);
232
233 sendLandUpdateToAvatarsOverMe();
234 }
235
236 public bool isEitherBannedOrRestricted(UUID avatar)
237 {
238 if (isBannedFromLand(avatar))
239 {
240 return true;
241 }
242 else if (isRestrictedFromLand(avatar))
243 {
244 return true;
245 }
246 return false;
247 }
248
249 public bool isBannedFromLand(UUID avatar)
250 {
251 if ((landData.Flags & (uint) Parcel.ParcelFlags.UseBanList) > 0)
252 {
253 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
254 entry.AgentID = avatar;
255 entry.Flags = AccessList.Ban;
256 entry.Time = new DateTime();
257 if (landData.ParcelAccessList.Contains(entry))
258 {
259 //They are banned, so lets send them a notice about this parcel
260 return true;
261 }
262 }
263 return false;
264 }
265
266 public bool isRestrictedFromLand(UUID avatar)
267 {
268 if ((landData.Flags & (uint) Parcel.ParcelFlags.UseAccessList) > 0)
269 {
270 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
271 entry.AgentID = avatar;
272 entry.Flags = AccessList.Access;
273 entry.Time = new DateTime();
274 if (!landData.ParcelAccessList.Contains(entry))
275 {
276 //They are not allowed in this parcel, but not banned, so lets send them a notice about this parcel
277 return true;
278 }
279 }
280 return false;
281 }
282
283 public void sendLandUpdateToClient(IClientAPI remote_client)
284 {
285 sendLandProperties(0, false, 0, remote_client);
286 }
287
288 public void sendLandUpdateToAvatarsOverMe()
289 {
290 List<ScenePresence> avatars = m_scene.GetAvatars();
291 ILandObject over = null;
292 for (int i = 0; i < avatars.Count; i++)
293 {
294 try
295 {
296 over =
297 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatars[i].AbsolutePosition.X), 0, 255),
298 Util.Clamp<int>((int)Math.Round(avatars[i].AbsolutePosition.Y), 0, 255));
299 }
300 catch (Exception)
301 {
302 m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatars[i].AbsolutePosition.X) + " y: " +
303 Math.Round(avatars[i].AbsolutePosition.Y));
304 }
305
306 if (over != null)
307 {
308 if (over.landData.LocalID == landData.LocalID)
309 {
310 if (((over.landData.Flags & (uint)Parcel.ParcelFlags.AllowDamage) != 0) && m_scene.RegionInfo.RegionSettings.AllowDamage)
311 avatars[i].Invulnerable = false;
312 else
313 avatars[i].Invulnerable = true;
314
315 sendLandUpdateToClient(avatars[i].ControllingClient);
316 }
317 }
318 }
319 }
320
321 #endregion
322
323 #region AccessList Functions
324
325 public List<UUID> createAccessListArrayByFlag(AccessList flag)
326 {
327 List<UUID> list = new List<UUID>();
328 foreach (ParcelManager.ParcelAccessEntry entry in landData.ParcelAccessList)
329 {
330 if (entry.Flags == flag)
331 {
332 list.Add(entry.AgentID);
333 }
334 }
335 if (list.Count == 0)
336 {
337 list.Add(UUID.Zero);
338 }
339
340 return list;
341 }
342
343 public void sendAccessList(UUID agentID, UUID sessionID, uint flags, int sequenceID,
344 IClientAPI remote_client)
345 {
346
347 if (flags == (uint) AccessList.Access || flags == (uint) AccessList.Both)
348 {
349 List<UUID> avatars = createAccessListArrayByFlag(AccessList.Access);
350 remote_client.SendLandAccessListData(avatars,(uint) AccessList.Access,landData.LocalID);
351 }
352
353 if (flags == (uint) AccessList.Ban || flags == (uint) AccessList.Both)
354 {
355 List<UUID> avatars = createAccessListArrayByFlag(AccessList.Ban);
356 remote_client.SendLandAccessListData(avatars, (uint)AccessList.Ban, landData.LocalID);
357 }
358 }
359
360 public void updateAccessList(uint flags, List<ParcelManager.ParcelAccessEntry> entries, IClientAPI remote_client)
361 {
362 LandData newData = landData.Copy();
363
364 if (entries.Count == 1 && entries[0].AgentID == UUID.Zero)
365 {
366 entries.Clear();
367 }
368
369 List<ParcelManager.ParcelAccessEntry> toRemove = new List<ParcelManager.ParcelAccessEntry>();
370 foreach (ParcelManager.ParcelAccessEntry entry in newData.ParcelAccessList)
371 {
372 if (entry.Flags == (AccessList)flags)
373 {
374 toRemove.Add(entry);
375 }
376 }
377
378 foreach (ParcelManager.ParcelAccessEntry entry in toRemove)
379 {
380 newData.ParcelAccessList.Remove(entry);
381 }
382 foreach (ParcelManager.ParcelAccessEntry entry in entries)
383 {
384 ParcelManager.ParcelAccessEntry temp = new ParcelManager.ParcelAccessEntry();
385 temp.AgentID = entry.AgentID;
386 temp.Time = new DateTime(); //Pointless? Yes.
387 temp.Flags = (AccessList)flags;
388
389 if (!newData.ParcelAccessList.Contains(temp))
390 {
391 newData.ParcelAccessList.Add(temp);
392 }
393 }
394
395 m_scene.LandChannel.UpdateLandObject(landData.LocalID, newData);
396 }
397
398 #endregion
399
400 #region Update Functions
401
402 public void updateLandBitmapByteArray()
403 {
404 landData.Bitmap = convertLandBitmapToBytes();
405 }
406
407 /// <summary>
408 /// Update all settings in land such as area, bitmap byte array, etc
409 /// </summary>
410 public void forceUpdateLandInfo()
411 {
412 updateAABBAndAreaValues();
413 updateLandBitmapByteArray();
414 }
415
416 public void setLandBitmapFromByteArray()
417 {
418 landBitmap = convertBytesToLandBitmap();
419 }
420
421 /// <summary>
422 /// Updates the AABBMin and AABBMax values after area/shape modification of the land object
423 /// </summary>
424 private void updateAABBAndAreaValues()
425 {
426 int min_x = 64;
427 int min_y = 64;
428 int max_x = 0;
429 int max_y = 0;
430 int tempArea = 0;
431 int x, y;
432 for (x = 0; x < 64; x++)
433 {
434 for (y = 0; y < 64; y++)
435 {
436 if (landBitmap[x, y] == true)
437 {
438 if (min_x > x) min_x = x;
439 if (min_y > y) min_y = y;
440 if (max_x < x) max_x = x;
441 if (max_y < y) max_y = y;
442 tempArea += 16; //16sqm peice of land
443 }
444 }
445 }
446 int tx = min_x * 4;
447 if (tx > 255)
448 tx = 255;
449 int ty = min_y * 4;
450 if (ty > 255)
451 ty = 255;
452 landData.AABBMin =
453 new Vector3((float) (min_x * 4), (float) (min_y * 4),
454 (float) m_scene.Heightmap[tx, ty]);
455
456 tx = max_x * 4;
457 if (tx > 255)
458 tx = 255;
459 ty = max_y * 4;
460 if (ty > 255)
461 ty = 255;
462 landData.AABBMax =
463 new Vector3((float) (max_x * 4), (float) (max_y * 4),
464 (float) m_scene.Heightmap[tx, ty]);
465 landData.Area = tempArea;
466 }
467
468 #endregion
469
470 #region Land Bitmap Functions
471
472 /// <summary>
473 /// Sets the land's bitmap manually
474 /// </summary>
475 /// <param name="bitmap">64x64 block representing where this land is on a map</param>
476 public void setLandBitmap(bool[,] bitmap)
477 {
478 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
479 {
480 //Throw an exception - The bitmap is not 64x64
481 //throw new Exception("Error: Invalid Parcel Bitmap");
482 }
483 else
484 {
485 //Valid: Lets set it
486 landBitmap = bitmap;
487 forceUpdateLandInfo();
488 }
489 }
490
491 /// <summary>
492 /// Gets the land's bitmap manually
493 /// </summary>
494 /// <returns></returns>
495 public bool[,] getLandBitmap()
496 {
497 return landBitmap;
498 }
499
500 /// <summary>
501 /// Full sim land object creation
502 /// </summary>
503 /// <returns></returns>
504 public bool[,] basicFullRegionLandBitmap()
505 {
506 return getSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize);
507 }
508
509 /// <summary>
510 /// Used to modify the bitmap between the x and y points. Points use 64 scale
511 /// </summary>
512 /// <param name="start_x"></param>
513 /// <param name="start_y"></param>
514 /// <param name="end_x"></param>
515 /// <param name="end_y"></param>
516 /// <returns></returns>
517 public bool[,] getSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
518 {
519 bool[,] tempBitmap = new bool[64,64];
520 tempBitmap.Initialize();
521
522 tempBitmap = modifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
523 return tempBitmap;
524 }
525
526 /// <summary>
527 /// Change a land bitmap at within a square and set those points to a specific value
528 /// </summary>
529 /// <param name="land_bitmap"></param>
530 /// <param name="start_x"></param>
531 /// <param name="start_y"></param>
532 /// <param name="end_x"></param>
533 /// <param name="end_y"></param>
534 /// <param name="set_value"></param>
535 /// <returns></returns>
536 public bool[,] modifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
537 bool set_value)
538 {
539 if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
540 {
541 //Throw an exception - The bitmap is not 64x64
542 //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
543 }
544
545 int x, y;
546 for (y = 0; y < 64; y++)
547 {
548 for (x = 0; x < 64; x++)
549 {
550 if (x >= start_x / 4 && x < end_x / 4
551 && y >= start_y / 4 && y < end_y / 4)
552 {
553 land_bitmap[x, y] = set_value;
554 }
555 }
556 }
557 return land_bitmap;
558 }
559
560 /// <summary>
561 /// Join the true values of 2 bitmaps together
562 /// </summary>
563 /// <param name="bitmap_base"></param>
564 /// <param name="bitmap_add"></param>
565 /// <returns></returns>
566 public bool[,] mergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
567 {
568 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2)
569 {
570 //Throw an exception - The bitmap is not 64x64
571 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps");
572 }
573 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
574 {
575 //Throw an exception - The bitmap is not 64x64
576 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
577 }
578
579 int x, y;
580 for (y = 0; y < 64; y++)
581 {
582 for (x = 0; x < 64; x++)
583 {
584 if (bitmap_add[x, y])
585 {
586 bitmap_base[x, y] = true;
587 }
588 }
589 }
590 return bitmap_base;
591 }
592
593 /// <summary>
594 /// Converts the land bitmap to a packet friendly byte array
595 /// </summary>
596 /// <returns></returns>
597 private byte[] convertLandBitmapToBytes()
598 {
599 byte[] tempConvertArr = new byte[512];
600 byte tempByte = 0;
601 int x, y, i, byteNum = 0;
602 i = 0;
603 for (y = 0; y < 64; y++)
604 {
605 for (x = 0; x < 64; x++)
606 {
607 tempByte = Convert.ToByte(tempByte | Convert.ToByte(landBitmap[x, y]) << (i++ % 8));
608 if (i % 8 == 0)
609 {
610 tempConvertArr[byteNum] = tempByte;
611 tempByte = (byte) 0;
612 i = 0;
613 byteNum++;
614 }
615 }
616 }
617 return tempConvertArr;
618 }
619
620 private bool[,] convertBytesToLandBitmap()
621 {
622 bool[,] tempConvertMap = new bool[64,64];
623 tempConvertMap.Initialize();
624 byte tempByte = 0;
625 int x = 0, y = 0, i = 0, bitNum = 0;
626 for (i = 0; i < 512; i++)
627 {
628 tempByte = landData.Bitmap[i];
629 for (bitNum = 0; bitNum < 8; bitNum++)
630 {
631 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
632 tempConvertMap[x, y] = bit;
633 x++;
634 if (x > 63)
635 {
636 x = 0;
637 y++;
638 }
639 }
640 }
641 return tempConvertMap;
642 }
643
644 #endregion
645
646 #region Object Select and Object Owner Listing
647
648 public void sendForceObjectSelect(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client)
649 {
650 if (m_scene.Permissions.CanEditParcel(remote_client.AgentId, this))
651 {
652 List<uint> resultLocalIDs = new List<uint>();
653 try
654 {
655 lock (primsOverMe)
656 {
657 foreach (SceneObjectGroup obj in primsOverMe)
658 {
659 if (obj.LocalId > 0)
660 {
661 if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == landData.OwnerID)
662 {
663 resultLocalIDs.Add(obj.LocalId);
664 }
665 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_GROUP && obj.GroupID == landData.GroupID && landData.GroupID != UUID.Zero)
666 {
667 resultLocalIDs.Add(obj.LocalId);
668 }
669 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
670 obj.OwnerID != remote_client.AgentId)
671 {
672 resultLocalIDs.Add(obj.LocalId);
673 }
674 else if (request_type == (int)ObjectReturnType.List && returnIDs.Contains(obj.OwnerID))
675 {
676 resultLocalIDs.Add(obj.LocalId);
677 }
678 }
679 }
680 }
681 } catch (InvalidOperationException)
682 {
683 m_log.Error("[LAND]: Unable to force select the parcel objects. Arr.");
684 }
685
686 remote_client.SendForceClientSelectObjects(resultLocalIDs);
687 }
688 }
689
690 /// <summary>
691 /// Notify the parcel owner each avatar that owns prims situated on their land. This notification includes
692 /// aggreagete details such as the number of prims.
693 ///
694 /// </summary>
695 /// <param name="remote_client">
696 /// A <see cref="IClientAPI"/>
697 /// </param>
698 public void sendLandObjectOwners(IClientAPI remote_client)
699 {
700 if (m_scene.Permissions.CanEditParcel(remote_client.AgentId, this))
701 {
702 Dictionary<UUID, int> primCount = new Dictionary<UUID, int>();
703
704 lock (primsOverMe)
705 {
706 try
707 {
708
709 foreach (SceneObjectGroup obj in primsOverMe)
710 {
711 try
712 {
713 if (!primCount.ContainsKey(obj.OwnerID))
714 {
715 primCount.Add(obj.OwnerID, 0);
716 }
717 }
718 catch (NullReferenceException)
719 {
720 m_log.Info("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
721 }
722 try
723 {
724 primCount[obj.OwnerID] += obj.PrimCount;
725 }
726 catch (KeyNotFoundException)
727 {
728 m_log.Error("[LAND]: Unable to match a prim with it's owner.");
729 }
730 }
731 }
732 catch (InvalidOperationException)
733 {
734 m_log.Error("[LAND]: Unable to Enumerate Land object arr.");
735 }
736 }
737
738 remote_client.SendLandObjectOwners(primCount);
739 }
740 }
741
742 public Dictionary<UUID, int> getLandObjectOwners()
743 {
744 Dictionary<UUID, int> ownersAndCount = new Dictionary<UUID, int>();
745 lock (primsOverMe)
746 {
747 try
748 {
749
750 foreach (SceneObjectGroup obj in primsOverMe)
751 {
752 if (!ownersAndCount.ContainsKey(obj.OwnerID))
753 {
754 ownersAndCount.Add(obj.OwnerID, 0);
755 }
756 ownersAndCount[obj.OwnerID] += obj.PrimCount;
757 }
758 }
759 catch (InvalidOperationException)
760 {
761 m_log.Error("[LAND]: Unable to enumerate land owners. arr.");
762 }
763
764 }
765 return ownersAndCount;
766 }
767
768 #endregion
769
770 #region Object Returning
771
772 public void returnObject(SceneObjectGroup obj)
773 {
774 SceneObjectGroup[] objs = new SceneObjectGroup[1];
775 objs[0] = obj;
776 m_scene.returnObjects(objs, obj.OwnerID);
777 }
778
779 public void returnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client)
780 {
781 Dictionary<UUID,List<SceneObjectGroup>> returns =
782 new Dictionary<UUID,List<SceneObjectGroup>>();
783
784 lock (primsOverMe)
785 {
786 if (type == (uint)ObjectReturnType.Owner)
787 {
788 foreach (SceneObjectGroup obj in primsOverMe)
789 {
790 if (obj.OwnerID == m_landData.OwnerID)
791 {
792 if (!returns.ContainsKey(obj.OwnerID))
793 returns[obj.OwnerID] =
794 new List<SceneObjectGroup>();
795 returns[obj.OwnerID].Add(obj);
796 }
797 }
798 }
799 else if (type == (uint)ObjectReturnType.Group && m_landData.GroupID != UUID.Zero)
800 {
801 foreach (SceneObjectGroup obj in primsOverMe)
802 {
803 if (obj.GroupID == m_landData.GroupID)
804 {
805 if (!returns.ContainsKey(obj.OwnerID))
806 returns[obj.OwnerID] =
807 new List<SceneObjectGroup>();
808 returns[obj.OwnerID].Add(obj);
809 }
810 }
811 }
812 else if (type == (uint)ObjectReturnType.Other)
813 {
814 foreach (SceneObjectGroup obj in primsOverMe)
815 {
816 if (obj.OwnerID != m_landData.OwnerID &&
817 (obj.GroupID != m_landData.GroupID ||
818 m_landData.GroupID == UUID.Zero))
819 {
820 if (!returns.ContainsKey(obj.OwnerID))
821 returns[obj.OwnerID] =
822 new List<SceneObjectGroup>();
823 returns[obj.OwnerID].Add(obj);
824 }
825 }
826 }
827 else if (type == (uint)ObjectReturnType.List)
828 {
829 List<UUID> ownerlist = new List<UUID>(owners);
830
831 foreach (SceneObjectGroup obj in primsOverMe)
832 {
833 if (ownerlist.Contains(obj.OwnerID))
834 {
835 if (!returns.ContainsKey(obj.OwnerID))
836 returns[obj.OwnerID] =
837 new List<SceneObjectGroup>();
838 returns[obj.OwnerID].Add(obj);
839 }
840 }
841 }
842 }
843
844 foreach (List<SceneObjectGroup> ol in returns.Values)
845 m_scene.returnObjects(ol.ToArray(), remote_client.AgentId);
846 }
847
848 #endregion
849
850 #region Object Adding/Removing from Parcel
851
852 public void resetLandPrimCounts()
853 {
854 landData.GroupPrims = 0;
855 landData.OwnerPrims = 0;
856 landData.OtherPrims = 0;
857 landData.SelectedPrims = 0;
858
859
860 lock (primsOverMe)
861 primsOverMe.Clear();
862 }
863
864 public void addPrimToCount(SceneObjectGroup obj)
865 {
866
867 UUID prim_owner = obj.OwnerID;
868 int prim_count = obj.PrimCount;
869
870 if (obj.IsSelected)
871 {
872 landData.SelectedPrims += prim_count;
873 }
874 else
875 {
876 if (prim_owner == landData.OwnerID)
877 {
878 landData.OwnerPrims += prim_count;
879 }
880 else if ((obj.GroupID == landData.GroupID ||
881 prim_owner == landData.GroupID) &&
882 landData.GroupID != UUID.Zero)
883 {
884 landData.GroupPrims += prim_count;
885 }
886 else
887 {
888 landData.OtherPrims += prim_count;
889 }
890 }
891
892 lock (primsOverMe)
893 primsOverMe.Add(obj);
894 }
895
896 public void removePrimFromCount(SceneObjectGroup obj)
897 {
898 lock (primsOverMe)
899 {
900 if (primsOverMe.Contains(obj))
901 {
902 UUID prim_owner = obj.OwnerID;
903 int prim_count = obj.PrimCount;
904
905 if (prim_owner == landData.OwnerID)
906 {
907 landData.OwnerPrims -= prim_count;
908 }
909 else if (obj.GroupID == landData.GroupID ||
910 prim_owner == landData.GroupID)
911 {
912 landData.GroupPrims -= prim_count;
913 }
914 else
915 {
916 landData.OtherPrims -= prim_count;
917 }
918
919 primsOverMe.Remove(obj);
920 }
921 }
922 }
923
924 #endregion
925
926 #endregion
927
928 #endregion
929 }
930}
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
new file mode 100644
index 0000000..1469f5d
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -0,0 +1,1498 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29using Nini.Config;
30using System;
31using System.Collections;
32using System.Collections.Generic;
33using System.Reflection;
34using log4net;
35using OpenSim;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.CoreModules.Framework;
40using OpenSim.Framework.Communications.Cache;
41
42namespace OpenSim.Region.CoreModules.World.Permissions
43{
44 public class PermissionsModule : IRegionModule
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 protected Scene m_scene;
49
50 #region Constants
51 // These are here for testing. They will be taken out
52
53 //private uint PERM_ALL = (uint)2147483647;
54 private uint PERM_COPY = (uint)32768;
55 //private uint PERM_MODIFY = (uint)16384;
56 private uint PERM_MOVE = (uint)524288;
57 //private uint PERM_TRANS = (uint)8192;
58 private uint PERM_LOCKED = (uint)540672;
59
60 /// <value>
61 /// Different user set names that come in from the configuration file.
62 /// </value>
63 enum UserSet
64 {
65 All,
66 Administrators
67 };
68
69 #endregion
70
71 #region Bypass Permissions / Debug Permissions Stuff
72
73 // Bypasses the permissions engine
74 private bool m_bypassPermissions = true;
75 private bool m_bypassPermissionsValue = true;
76 private bool m_propagatePermissions = false;
77 private bool m_debugPermissions = false;
78 private bool m_allowGridGods = false;
79 private bool m_RegionOwnerIsGod = false;
80 private bool m_ParcelOwnerIsGod = false;
81
82 /// <value>
83 /// The set of users that are allowed to create scripts. This is only active if permissions are not being
84 /// bypassed. This overrides normal permissions.
85 /// </value>
86 private UserSet m_allowedScriptCreators = UserSet.All;
87
88 /// <value>
89 /// The set of users that are allowed to edit (save) scripts. This is only active if
90 /// permissions are not being bypassed. This overrides normal permissions.-
91 /// </value>
92 private UserSet m_allowedScriptEditors = UserSet.All;
93
94 #endregion
95
96 #region IRegionModule Members
97
98 public void Initialise(Scene scene, IConfigSource config)
99 {
100 m_scene = scene;
101
102 IConfig myConfig = config.Configs["Startup"];
103
104 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule");
105
106 List<string> modules=new List<string>(permissionModules.Split(','));
107
108 if (!modules.Contains("DefaultPermissionsModule"))
109 return;
110
111 m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false);
112 m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true);
113 m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true);
114 m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true);
115 m_ParcelOwnerIsGod = myConfig.GetBoolean("parcel_owner_is_god", true);
116
117 m_allowedScriptCreators
118 = ParseUserSetConfigSetting(myConfig, "allowed_script_creators", m_allowedScriptCreators);
119 m_allowedScriptEditors
120 = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors);
121
122 if (m_bypassPermissions)
123 m_log.Info("[PERMISSIONS]: serviceside_object_permissions = false in ini file so disabling all region service permission checks");
124 else
125 m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks");
126
127 //Register functions with Scene External Checks!
128 m_scene.Permissions.AddBypassPermissionsHandler(BypassPermissions); //FULLY IMPLEMENTED
129 m_scene.Permissions.AddSetBypassPermissionsHandler(SetBypassPermissions); //FULLY IMPLEMENTED
130 m_scene.Permissions.AddPropagatePermissionsHandler(PropagatePermissions); //FULLY IMPLEMENTED
131 m_scene.Permissions.AddGenerateClientFlagsHandler(GenerateClientFlags); //NOT YET FULLY IMPLEMENTED
132 m_scene.Permissions.AddAbandonParcelHandler(CanAbandonParcel); //FULLY IMPLEMENTED
133 m_scene.Permissions.AddReclaimParcelHandler(CanReclaimParcel); //FULLY IMPLEMENTED
134 m_scene.Permissions.AddIsGodHandler(IsGod); //FULLY IMPLEMENTED
135 m_scene.Permissions.AddDuplicateObjectHandler(CanDuplicateObject); //FULLY IMPLEMENTED
136 m_scene.Permissions.AddDeleteObjectHandler(CanDeleteObject); //MAYBE FULLY IMPLEMENTED
137 m_scene.Permissions.AddEditObjectHandler(CanEditObject);//MAYBE FULLY IMPLEMENTED
138 m_scene.Permissions.AddEditParcelHandler(CanEditParcel); //FULLY IMPLEMENTED
139 m_scene.Permissions.AddInstantMessageHandler(CanInstantMessage); //FULLY IMPLEMENTED
140 m_scene.Permissions.AddInventoryTransferHandler(CanInventoryTransfer); //NOT YET IMPLEMENTED
141 m_scene.Permissions.AddIssueEstateCommandHandler(CanIssueEstateCommand); //FULLY IMPLEMENTED
142 m_scene.Permissions.AddMoveObjectHandler(CanMoveObject); //HOPEFULLY FULLY IMPLEMENTED
143 m_scene.Permissions.AddObjectEntryHandler(CanObjectEntry); //FULLY IMPLEMENTED
144 m_scene.Permissions.AddReturnObjectHandler(CanReturnObject); //NOT YET IMPLEMENTED
145 m_scene.Permissions.AddRezObjectHandler(CanRezObject); //HOPEFULLY FULLY IMPLEMENTED
146 m_scene.Permissions.AddRunConsoleCommandHandler(CanRunConsoleCommand); //FULLY IMPLEMENTED
147 m_scene.Permissions.AddRunScriptHandler(CanRunScript); //NOT YET IMPLEMENTED
148 m_scene.Permissions.AddSellParcelHandler(CanSellParcel); //FULLY IMPLEMENTED
149 m_scene.Permissions.AddTakeObjectHandler(CanTakeObject); //FULLY IMPLEMENTED
150 m_scene.Permissions.AddTakeCopyObjectHandler(CanTakeCopyObject); //FULLY IMPLEMENTED
151 m_scene.Permissions.AddTerraformLandHandler(CanTerraformLand); //FULL IMPLEMENTED (POINT ONLY!!! NOT AREA!!!)
152 m_scene.Permissions.AddCanLinkObjectHandler(CanLinkObject); //NOT YET IMPLEMENTED
153 m_scene.Permissions.AddCanDelinkObjectHandler(CanDelinkObject); //NOT YET IMPLEMENTED
154 m_scene.Permissions.AddCanBuyLandHandler(CanBuyLand); //NOT YET IMPLEMENTED
155
156 m_scene.Permissions.AddViewNotecardHandler(CanViewNotecard); //NOT YET IMPLEMENTED
157 m_scene.Permissions.AddViewScriptHandler(CanViewScript); //NOT YET IMPLEMENTED
158 m_scene.Permissions.AddEditNotecardHandler(CanEditNotecard); //NOT YET IMPLEMENTED
159 m_scene.Permissions.AddEditScriptHandler(CanEditScript); //NOT YET IMPLEMENTED
160
161 m_scene.Permissions.AddCanCreateObjectInventoryHandler(CanCreateObjectInventory); //NOT IMPLEMENTED HERE
162 m_scene.Permissions.AddEditObjectInventoryHandler(CanEditObjectInventory);//MAYBE FULLY IMPLEMENTED
163 m_scene.Permissions.AddCanCopyObjectInventoryHandler(CanCopyObjectInventory); //NOT YET IMPLEMENTED
164 m_scene.Permissions.AddCanDeleteObjectInventoryHandler(CanDeleteObjectInventory); //NOT YET IMPLEMENTED
165 m_scene.Permissions.AddResetScriptHandler(CanResetScript);
166
167 m_scene.Permissions.AddCanCreateUserInventoryHandler(CanCreateUserInventory); //NOT YET IMPLEMENTED
168 m_scene.Permissions.AddCanCopyUserInventoryHandler(CanCopyUserInventory); //NOT YET IMPLEMENTED
169 m_scene.Permissions.AddCanEditUserInventoryHandler(CanEditUserInventory); //NOT YET IMPLEMENTED
170 m_scene.Permissions.AddCanDeleteUserInventoryHandler(CanDeleteUserInventory); //NOT YET IMPLEMENTED
171
172 m_scene.Permissions.AddCanTeleportHandler(CanTeleport); //NOT YET IMPLEMENTED
173
174 m_scene.AddCommand("permissions", "bypass permissions",
175 "bypass permissions <true / false>",
176 "Bypass permission checks",
177 HandleBypassPermissions);
178
179 m_scene.AddCommand("permissions", "force permissions",
180 "force permissions <true / false>",
181 "Force permissions on or off",
182 HandleForcePermissions);
183
184 m_scene.AddCommand("permissions", "debug permissions",
185 "debug permissions <true / false>",
186 "Enable permissions debugging",
187 HandleDebugPermissions);
188 }
189
190 public void HandleBypassPermissions(string module, string[] args)
191 {
192 if (m_scene.ConsoleScene() != null &&
193 m_scene.ConsoleScene() != m_scene)
194 {
195 return;
196 }
197
198 if (args.Length > 2)
199 {
200 bool val;
201
202 if (!bool.TryParse(args[2], out val))
203 return;
204
205 m_bypassPermissions = val;
206
207 m_log.InfoFormat(
208 "[PERMISSIONS]: Set permissions bypass to {0} for {1}",
209 m_bypassPermissions, m_scene.RegionInfo.RegionName);
210 }
211 }
212
213 public void HandleForcePermissions(string module, string[] args)
214 {
215 if (m_scene.ConsoleScene() != null &&
216 m_scene.ConsoleScene() != m_scene)
217 {
218 return;
219 }
220
221 if (!m_bypassPermissions)
222 {
223 m_log.Error("[PERMISSIONS] Permissions can't be forced unless they are bypassed first");
224 return;
225 }
226
227 if (args.Length > 2)
228 {
229 bool val;
230
231 if (!bool.TryParse(args[2], out val))
232 return;
233
234 m_bypassPermissionsValue = val;
235
236 m_log.InfoFormat("[PERMISSIONS] Forced permissions to {0} in {1}", m_bypassPermissionsValue, m_scene.RegionInfo.RegionName);
237 }
238 }
239
240 public void HandleDebugPermissions(string module, string[] args)
241 {
242 if (m_scene.ConsoleScene() != null &&
243 m_scene.ConsoleScene() != m_scene)
244 {
245 return;
246 }
247
248 if (args.Length > 2)
249 {
250 bool val;
251
252 if (!bool.TryParse(args[2], out val))
253 return;
254
255 m_debugPermissions = val;
256
257 m_log.InfoFormat("[PERMISSIONS] Set permissions debugging to {0} in {1}", m_debugPermissions, m_scene.RegionInfo.RegionName);
258 }
259 }
260
261 public void PostInitialise()
262 {
263 }
264
265 public void Close()
266 {
267 }
268
269 public string Name
270 {
271 get { return "PermissionsModule"; }
272 }
273
274 public bool IsSharedModule
275 {
276 get { return false; }
277 }
278
279 #endregion
280
281 #region Helper Functions
282 protected void SendPermissionError(UUID user, string reason)
283 {
284 m_scene.EventManager.TriggerPermissionError(user, reason);
285 }
286
287 protected void DebugPermissionInformation(string permissionCalled)
288 {
289 if (m_debugPermissions)
290 m_log.Debug("[PERMISSIONS]: " + permissionCalled + " was called from " + m_scene.RegionInfo.RegionName);
291 }
292
293 /// <summary>
294 /// Parse a user set configuration setting
295 /// </summary>
296 /// <param name="config"></param>
297 /// <param name="settingName"></param>
298 /// <param name="defaultValue">The default value for this attribute</param>
299 /// <returns>The parsed value</returns>
300 private static UserSet ParseUserSetConfigSetting(IConfig config, string settingName, UserSet defaultValue)
301 {
302 UserSet userSet = defaultValue;
303
304 string rawSetting = config.GetString(settingName, defaultValue.ToString());
305
306 // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term
307 // this should disappear.
308 if ("gods" == rawSetting.ToLower())
309 rawSetting = UserSet.Administrators.ToString();
310
311 // Doing it this was so that we can do a case insensitive conversion
312 try
313 {
314 userSet = (UserSet)Enum.Parse(typeof(UserSet), rawSetting, true);
315 }
316 catch
317 {
318 m_log.ErrorFormat(
319 "[PERMISSIONS]: {0} is not a valid {1} value, setting to {2}",
320 rawSetting, settingName, userSet);
321 }
322
323 m_log.DebugFormat("[PERMISSIONS]: {0} {1}", settingName, userSet);
324
325 return userSet;
326 }
327
328 /// <summary>
329 /// Is the given user an administrator (in other words, a god)?
330 /// </summary>
331 /// <param name="user"></param>
332 /// <returns></returns>
333 protected bool IsAdministrator(UUID user)
334 {
335 if (m_scene.RegionInfo.MasterAvatarAssignedUUID != UUID.Zero)
336 {
337 if (m_RegionOwnerIsGod && (m_scene.RegionInfo.MasterAvatarAssignedUUID == user))
338 return true;
339 }
340
341 if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero)
342 {
343 if (m_scene.RegionInfo.EstateSettings.EstateOwner == user)
344 return true;
345 }
346
347 if (m_allowGridGods)
348 {
349 CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(user);
350 if (profile != null && profile.UserProfile != null)
351 {
352 if (profile.UserProfile.GodLevel >= 200)
353 return true;
354 }
355 else
356 {
357 m_log.ErrorFormat("[PERMISSIONS]: Could not find user {0} for administrator check", user);
358 }
359 }
360
361 return false;
362 }
363
364 protected bool IsEstateManager(UUID user)
365 {
366 return m_scene.RegionInfo.EstateSettings.IsEstateManager(user);
367 }
368#endregion
369
370 public bool PropagatePermissions()
371 {
372 if (m_bypassPermissions)
373 return false;
374
375 return m_propagatePermissions;
376 }
377
378 public bool BypassPermissions()
379 {
380 return m_bypassPermissions;
381 }
382
383 public void SetBypassPermissions(bool value)
384 {
385 m_bypassPermissions=value;
386 }
387
388 #region Object Permissions
389
390 public uint GenerateClientFlags(UUID user, UUID objID)
391 {
392 // Here's the way this works,
393 // ObjectFlags and Permission flags are two different enumerations
394 // ObjectFlags, however, tells the client to change what it will allow the user to do.
395 // So, that means that all of the permissions type ObjectFlags are /temporary/ and only
396 // supposed to be set when customizing the objectflags for the client.
397
398 // These temporary objectflags get computed and added in this function based on the
399 // Permission mask that's appropriate!
400 // Outside of this method, they should never be added to objectflags!
401 // -teravus
402
403 SceneObjectPart task = m_scene.GetSceneObjectPart(objID);
404
405 // this shouldn't ever happen.. return no permissions/objectflags.
406 if (task == null)
407 return (uint)0;
408
409 uint objflags = task.GetEffectiveObjectFlags();
410 UUID objectOwner = task.OwnerID;
411
412
413 // Remove any of the objectFlags that are temporary. These will get added back if appropriate
414 // in the next bit of code
415
416 // libomv will moan about PrimFlags.ObjectYouOfficer being
417 // deprecated
418 #pragma warning disable 0612
419 objflags &= (uint)
420 ~(PrimFlags.ObjectCopy | // Tells client you can copy the object
421 PrimFlags.ObjectModify | // tells client you can modify the object
422 PrimFlags.ObjectMove | // tells client that you can move the object (only, no mod)
423 PrimFlags.ObjectTransfer | // tells the client that you can /take/ the object if you don't own it
424 PrimFlags.ObjectYouOwner | // Tells client that you're the owner of the object
425 PrimFlags.ObjectAnyOwner | // Tells client that someone owns the object
426 PrimFlags.ObjectOwnerModify | // Tells client that you're the owner of the object
427 PrimFlags.ObjectYouOfficer // Tells client that you've got group object editing permission. Used when ObjectGroupOwned is set
428 );
429 #pragma warning restore 0612
430
431 // Creating the three ObjectFlags options for this method to choose from.
432 // Customize the OwnerMask
433 uint objectOwnerMask = ApplyObjectModifyMasks(task.OwnerMask, objflags);
434 objectOwnerMask |= (uint)PrimFlags.ObjectYouOwner | (uint)PrimFlags.ObjectAnyOwner | (uint)PrimFlags.ObjectOwnerModify;
435
436 // Customize the GroupMask
437 // uint objectGroupMask = ApplyObjectModifyMasks(task.GroupMask, objflags);
438
439 // Customize the EveryoneMask
440 uint objectEveryoneMask = ApplyObjectModifyMasks(task.EveryoneMask, objflags);
441
442
443 // Hack to allow collaboration until Groups and Group Permissions are implemented
444 if ((objectEveryoneMask & (uint)PrimFlags.ObjectMove) != 0)
445 objectEveryoneMask |= (uint)PrimFlags.ObjectModify;
446
447 if (m_bypassPermissions)
448 return objectOwnerMask;
449
450 // Object owners should be able to edit their own content
451 if (user == objectOwner)
452 {
453 return objectOwnerMask;
454 }
455
456 // Users should be able to edit what is over their land.
457 ILandObject parcel = m_scene.LandChannel.GetLandObject(task.AbsolutePosition.X, task.AbsolutePosition.Y);
458 if (parcel != null && parcel.landData.OwnerID == user && m_ParcelOwnerIsGod)
459 return objectOwnerMask;
460
461 // Admin objects should not be editable by the above
462 if (IsAdministrator(objectOwner))
463 return objectEveryoneMask;
464
465 // Estate users should be able to edit anything in the sim
466 if (IsEstateManager(user) && m_RegionOwnerIsGod)
467 return objectOwnerMask;
468
469 // Admin should be able to edit anything in the sim (including admin objects)
470 if (IsAdministrator(user))
471 return objectOwnerMask;
472
473
474 return objectEveryoneMask;
475 }
476
477 private uint ApplyObjectModifyMasks(uint setPermissionMask, uint objectFlagsMask)
478 {
479 // We are adding the temporary objectflags to the object's objectflags based on the
480 // permission flag given. These change the F flags on the client.
481
482 if ((setPermissionMask & (uint)PermissionMask.Copy) != 0)
483 {
484 objectFlagsMask |= (uint)PrimFlags.ObjectCopy;
485 }
486
487 if ((setPermissionMask & (uint)PermissionMask.Move) != 0)
488 {
489 objectFlagsMask |= (uint)PrimFlags.ObjectMove;
490 }
491
492 if ((setPermissionMask & (uint)PermissionMask.Modify) != 0)
493 {
494 objectFlagsMask |= (uint)PrimFlags.ObjectModify;
495 }
496
497 if ((setPermissionMask & (uint)PermissionMask.Transfer) != 0)
498 {
499 objectFlagsMask |= (uint)PrimFlags.ObjectTransfer;
500 }
501
502 return objectFlagsMask;
503 }
504
505 /// <summary>
506 /// General permissions checks for any operation involving an object. These supplement more specific checks
507 /// implemented by callers.
508 /// </summary>
509 /// <param name="currentUser"></param>
510 /// <param name="objId"></param>
511 /// <param name="denyOnLocked"></param>
512 /// <returns></returns>
513 protected bool GenericObjectPermission(UUID currentUser, UUID objId, bool denyOnLocked)
514 {
515 // Default: deny
516 bool permission = false;
517 bool locked = false;
518
519 if (!m_scene.Entities.ContainsKey(objId))
520 {
521 return false;
522 }
523
524 // If it's not an object, we cant edit it.
525 if ((!(m_scene.Entities[objId] is SceneObjectGroup)))
526 {
527 return false;
528 }
529
530 SceneObjectGroup group = (SceneObjectGroup)m_scene.Entities[objId];
531
532 UUID objectOwner = group.OwnerID;
533 locked = ((group.RootPart.OwnerMask & PERM_LOCKED) == 0);
534
535 // People shouldn't be able to do anything with locked objects, except the Administrator
536 // The 'set permissions' runs through a different permission check, so when an object owner
537 // sets an object locked, the only thing that they can do is unlock it.
538 //
539 // Nobody but the object owner can set permissions on an object
540 //
541
542 if (locked && (!IsAdministrator(currentUser)) && denyOnLocked)
543 {
544 return false;
545 }
546
547 // Object owners should be able to edit their own content
548 if (currentUser == objectOwner)
549 {
550 permission = true;
551 }
552 else if (group.IsAttachment)
553 {
554 permission = false;
555 }
556
557 // Users should be able to edit what is over their land.
558 ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y);
559 if ((parcel != null) && (parcel.landData.OwnerID == currentUser))
560 {
561 permission = true;
562 }
563
564 // Estate users should be able to edit anything in the sim
565 if (IsEstateManager(currentUser))
566 {
567 permission = true;
568 }
569
570 // Admin objects should not be editable by the above
571 if (IsAdministrator(objectOwner))
572 {
573 permission = false;
574 }
575
576 // Admin should be able to edit anything in the sim (including admin objects)
577 if (IsAdministrator(currentUser))
578 {
579 permission = true;
580 }
581
582 return permission;
583 }
584
585 #endregion
586
587 #region Generic Permissions
588 protected bool GenericCommunicationPermission(UUID user, UUID target)
589 {
590 // Setting this to true so that cool stuff can happen until we define what determines Generic Communication Permission
591 bool permission = true;
592 string reason = "Only registered users may communicate with another account.";
593
594 // Uhh, we need to finish this before we enable it.. because it's blocking all sorts of goodies and features
595 if (IsAdministrator(user))
596 permission = true;
597
598 if (IsEstateManager(user))
599 permission = true;
600
601 if (!permission)
602 SendPermissionError(user, reason);
603
604 return permission;
605 }
606
607 public bool GenericEstatePermission(UUID user)
608 {
609 // Default: deny
610 bool permission = false;
611
612 // Estate admins should be able to use estate tools
613 if (IsEstateManager(user))
614 permission = true;
615
616 // Administrators always have permission
617 if (IsAdministrator(user))
618 permission = true;
619
620 return permission;
621 }
622
623 protected bool GenericParcelPermission(UUID user, ILandObject parcel)
624 {
625 bool permission = false;
626
627 if (parcel.landData.OwnerID == user)
628 {
629 permission = true;
630 }
631
632 if (parcel.landData.IsGroupOwned)
633 {
634 // TODO: Need to do some extra checks here. Requires group code.
635 }
636
637 if (IsEstateManager(user))
638 {
639 permission = true;
640 }
641
642 if (IsAdministrator(user))
643 {
644 permission = true;
645 }
646
647 return permission;
648 }
649
650 protected bool GenericParcelPermission(UUID user, Vector3 pos)
651 {
652 ILandObject parcel = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
653 if (parcel == null) return false;
654 return GenericParcelPermission(user, parcel);
655 }
656#endregion
657
658 #region Permission Checks
659 private bool CanAbandonParcel(UUID user, ILandObject parcel, Scene scene)
660 {
661 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
662 if (m_bypassPermissions) return m_bypassPermissionsValue;
663
664 return GenericParcelPermission(user, parcel);
665 }
666
667 private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene)
668 {
669 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
670 if (m_bypassPermissions) return m_bypassPermissionsValue;
671
672 return GenericParcelPermission(user, parcel);
673 }
674
675 private bool IsGod(UUID user, Scene scene)
676 {
677 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
678 if (m_bypassPermissions) return m_bypassPermissionsValue;
679
680 return IsAdministrator(user);
681 }
682
683 private bool CanDuplicateObject(int objectCount, UUID objectID, UUID owner, Scene scene, Vector3 objectPosition)
684 {
685 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
686 if (m_bypassPermissions) return m_bypassPermissionsValue;
687
688 if (!GenericObjectPermission(owner, objectID, true))
689 {
690 //They can't even edit the object
691 return false;
692 }
693
694 SceneObjectPart part = scene.GetSceneObjectPart(objectID);
695 if (part == null)
696 return false;
697
698 if ((part.OwnerMask & PERM_COPY) == 0)
699 return false;
700
701 if ((part.ParentGroup.GetEffectivePermissions() & PERM_COPY) == 0)
702 return false;
703
704 //If they can rez, they can duplicate
705 return CanRezObject(objectCount, owner, objectPosition, scene);
706 }
707
708 private bool CanDeleteObject(UUID objectID, UUID deleter, Scene scene)
709 {
710 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
711 if (m_bypassPermissions) return m_bypassPermissionsValue;
712
713 return GenericObjectPermission(deleter, objectID, false);
714 }
715
716 private bool CanEditObject(UUID objectID, UUID editorID, Scene scene)
717 {
718 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
719 if (m_bypassPermissions) return m_bypassPermissionsValue;
720
721
722 return GenericObjectPermission(editorID, objectID, false);
723 }
724
725 private bool CanEditObjectInventory(UUID objectID, UUID editorID, Scene scene)
726 {
727 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
728 if (m_bypassPermissions) return m_bypassPermissionsValue;
729
730 SceneObjectPart part = m_scene.GetSceneObjectPart(objectID);
731
732 // If we selected a sub-prim to edit, the objectID won't represent the object, but only a part.
733 // We have to check the permissions of the group, though.
734 if (part.ParentID != 0)
735 {
736 objectID = part.ParentUUID;
737 part = m_scene.GetSceneObjectPart(objectID);
738 }
739
740 // TODO: add group support!
741 //
742 if (part.OwnerID != editorID)
743 return false;
744
745 return GenericObjectPermission(editorID, objectID, false);
746 }
747
748 private bool CanEditParcel(UUID user, ILandObject parcel, Scene scene)
749 {
750 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
751 if (m_bypassPermissions) return m_bypassPermissionsValue;
752
753 return GenericParcelPermission(user, parcel);
754 }
755
756 /// <summary>
757 /// Check whether the specified user can edit the given script
758 /// </summary>
759 /// <param name="script"></param>
760 /// <param name="objectID"></param>
761 /// <param name="user"></param>
762 /// <param name="scene"></param>
763 /// <returns></returns>
764 private bool CanEditScript(UUID script, UUID objectID, UUID user, Scene scene)
765 {
766 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
767 if (m_bypassPermissions) return m_bypassPermissionsValue;
768
769 if (m_allowedScriptEditors == UserSet.Administrators && !IsAdministrator(user))
770 return false;
771
772 // Ordinarily, if you can view it, you can edit it
773 // There is no viewing a no mod script
774 //
775 return CanViewScript(script, objectID, user, scene);
776 }
777
778 /// <summary>
779 /// Check whether the specified user can edit the given notecard
780 /// </summary>
781 /// <param name="notecard"></param>
782 /// <param name="objectID"></param>
783 /// <param name="user"></param>
784 /// <param name="scene"></param>
785 /// <returns></returns>
786 private bool CanEditNotecard(UUID notecard, UUID objectID, UUID user, Scene scene)
787 {
788 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
789 if (m_bypassPermissions) return m_bypassPermissionsValue;
790
791 if (objectID == UUID.Zero) // User inventory
792 {
793 CachedUserInfo userInfo =
794 scene.CommsManager.UserProfileCacheService.GetUserDetails(user);
795
796 if (userInfo == null)
797 {
798 m_log.ErrorFormat("[PERMISSIONS]: Could not find user {0} for edit notecard check", user);
799 return false;
800 }
801
802 if (userInfo.RootFolder == null)
803 return false;
804
805 InventoryItemBase assetRequestItem = userInfo.RootFolder.FindItem(notecard);
806 if (assetRequestItem == null) // Library item
807 {
808 assetRequestItem = scene.CommsManager.UserProfileCacheService.LibraryRoot.FindItem(notecard);
809
810 if (assetRequestItem != null) // Implicitly readable
811 return true;
812 }
813
814 // Notecards must be both mod and copy to be saveable
815 // This is because of they're not copy, you can't read
816 // them, and if they're not mod, well, then they're
817 // not mod. Duh.
818 //
819 if ((assetRequestItem.CurrentPermissions &
820 ((uint)PermissionMask.Modify |
821 (uint)PermissionMask.Copy)) !=
822 ((uint)PermissionMask.Modify |
823 (uint)PermissionMask.Copy))
824 return false;
825 }
826 else // Prim inventory
827 {
828 SceneObjectPart part = scene.GetSceneObjectPart(objectID);
829
830 if (part == null)
831 return false;
832
833 if (part.OwnerID != user)
834 return false;
835
836 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
837 return false;
838
839 TaskInventoryItem ti = part.Inventory.GetInventoryItem(notecard);
840
841 if (ti == null)
842 return false;
843
844 if (ti.OwnerID != user)
845 return false;
846
847 // Require full perms
848 if ((ti.CurrentPermissions &
849 ((uint)PermissionMask.Modify |
850 (uint)PermissionMask.Copy)) !=
851 ((uint)PermissionMask.Modify |
852 (uint)PermissionMask.Copy))
853 return false;
854 }
855
856 return true;
857 }
858
859 private bool CanInstantMessage(UUID user, UUID target, Scene startScene)
860 {
861 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
862 if (m_bypassPermissions) return m_bypassPermissionsValue;
863
864 // If the sender is an object, check owner instead
865 //
866 SceneObjectPart part = startScene.GetSceneObjectPart(user);
867 if (part != null)
868 user = part.OwnerID;
869
870 return GenericCommunicationPermission(user, target);
871 }
872
873 private bool CanInventoryTransfer(UUID user, UUID target, Scene startScene)
874 {
875 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
876 if (m_bypassPermissions) return m_bypassPermissionsValue;
877
878 return GenericCommunicationPermission(user, target);
879 }
880
881 private bool CanIssueEstateCommand(UUID user, Scene requestFromScene, bool ownerCommand)
882 {
883 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
884 if (m_bypassPermissions) return m_bypassPermissionsValue;
885
886 if (IsAdministrator(user))
887 return true;
888
889 if (m_scene.RegionInfo.EstateSettings.IsEstateOwner(user))
890 return true;
891
892 if (ownerCommand)
893 return false;
894
895 return GenericEstatePermission(user);
896 }
897
898 private bool CanMoveObject(UUID objectID, UUID moverID, Scene scene)
899 {
900 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
901 if (m_bypassPermissions)
902 {
903 SceneObjectPart part = scene.GetSceneObjectPart(objectID);
904 if (part.OwnerID != moverID)
905 {
906 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted)
907 {
908 if (part.ParentGroup.IsAttachment)
909 return false;
910 }
911 }
912 return m_bypassPermissionsValue;
913 }
914
915 bool permission = GenericObjectPermission(moverID, objectID, true);
916 if (!permission)
917 {
918 if (!m_scene.Entities.ContainsKey(objectID))
919 {
920 return false;
921 }
922
923 // The client
924 // may request to edit linked parts, and therefore, it needs
925 // to also check for SceneObjectPart
926
927 // If it's not an object, we cant edit it.
928 if ((!(m_scene.Entities[objectID] is SceneObjectGroup)))
929 {
930 return false;
931 }
932
933
934 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
935
936
937 // UUID taskOwner = null;
938 // Added this because at this point in time it wouldn't be wise for
939 // the administrator object permissions to take effect.
940 // UUID objectOwner = task.OwnerID;
941
942 // Anyone can move
943 if ((task.RootPart.EveryoneMask & PERM_MOVE) != 0)
944 permission = true;
945
946 // Locked
947 if ((task.RootPart.OwnerMask & PERM_LOCKED) == 0)
948 permission = false;
949 }
950 else
951 {
952 bool locked = false;
953 if (!m_scene.Entities.ContainsKey(objectID))
954 {
955 return false;
956 }
957
958 // If it's not an object, we cant edit it.
959 if ((!(m_scene.Entities[objectID] is SceneObjectGroup)))
960 {
961 return false;
962 }
963
964 SceneObjectGroup group = (SceneObjectGroup)m_scene.Entities[objectID];
965
966 UUID objectOwner = group.OwnerID;
967 locked = ((group.RootPart.OwnerMask & PERM_LOCKED) == 0);
968
969 // This is an exception to the generic object permission.
970 // Administrators who lock their objects should not be able to move them,
971 // however generic object permission should return true.
972 // This keeps locked objects from being affected by random click + drag actions by accident
973 // and allows the administrator to grab or delete a locked object.
974
975 // Administrators and estate managers are still able to click+grab locked objects not
976 // owned by them in the scene
977 // This is by design.
978
979 if (locked && (moverID == objectOwner))
980 return false;
981 }
982 return permission;
983 }
984
985 private bool CanObjectEntry(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene)
986 {
987 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
988 if (m_bypassPermissions) return m_bypassPermissionsValue;
989
990 if ((newPoint.X > 257f || newPoint.X < -1f || newPoint.Y > 257f || newPoint.Y < -1f))
991 {
992 return true;
993 }
994
995 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
996
997 ILandObject land = m_scene.LandChannel.GetLandObject(newPoint.X, newPoint.Y);
998
999 if (!enteringRegion)
1000 {
1001 ILandObject fromland = m_scene.LandChannel.GetLandObject(task.AbsolutePosition.X, task.AbsolutePosition.Y);
1002
1003 if (fromland == land) // Not entering
1004 return true;
1005 }
1006
1007 if (land == null)
1008 {
1009 return false;
1010 }
1011
1012 if ((land.landData.Flags & ((int)Parcel.ParcelFlags.AllowAPrimitiveEntry)) != 0)
1013 {
1014 return true;
1015 }
1016
1017 //TODO: check for group rights
1018
1019 if (!m_scene.Entities.ContainsKey(objectID))
1020 {
1021 return false;
1022 }
1023
1024 // If it's not an object, we cant edit it.
1025 if (!(m_scene.Entities[objectID] is SceneObjectGroup))
1026 {
1027 return false;
1028 }
1029
1030
1031 if (GenericParcelPermission(task.OwnerID, newPoint))
1032 {
1033 return true;
1034 }
1035
1036 //Otherwise, false!
1037 return false;
1038 }
1039
1040 private bool CanReturnObject(UUID objectID, UUID returnerID, Scene scene)
1041 {
1042 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1043 if (m_bypassPermissions) return m_bypassPermissionsValue;
1044
1045 return GenericObjectPermission(returnerID, objectID, false);
1046 }
1047
1048 private bool CanRezObject(int objectCount, UUID owner, Vector3 objectPosition, Scene scene)
1049 {
1050 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1051 if (m_bypassPermissions) return m_bypassPermissionsValue;
1052
1053 bool permission = false;
1054
1055 ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
1056 if (land == null) return false;
1057
1058 if ((land.landData.Flags & ((int)Parcel.ParcelFlags.CreateObjects)) ==
1059 (int)Parcel.ParcelFlags.CreateObjects)
1060 permission = true;
1061
1062 //TODO: check for group rights
1063
1064 if (IsAdministrator(owner))
1065 {
1066 permission = true;
1067 }
1068
1069 if (GenericParcelPermission(owner, objectPosition))
1070 {
1071 permission = true;
1072 }
1073
1074 return permission;
1075 }
1076
1077 private bool CanRunConsoleCommand(UUID user, Scene requestFromScene)
1078 {
1079 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1080 if (m_bypassPermissions) return m_bypassPermissionsValue;
1081
1082
1083 return IsAdministrator(user);
1084 }
1085
1086 private bool CanRunScript(UUID script, UUID objectID, UUID user, Scene scene)
1087 {
1088 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1089 if (m_bypassPermissions) return m_bypassPermissionsValue;
1090
1091 return true;
1092 }
1093
1094 private bool CanSellParcel(UUID user, ILandObject parcel, Scene scene)
1095 {
1096 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1097 if (m_bypassPermissions) return m_bypassPermissionsValue;
1098
1099 return GenericParcelPermission(user, parcel);
1100 }
1101
1102 private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene)
1103 {
1104 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1105 if (m_bypassPermissions) return m_bypassPermissionsValue;
1106
1107 return GenericObjectPermission(stealer,objectID, false);
1108 }
1109
1110 private bool CanTakeCopyObject(UUID objectID, UUID userID, Scene inScene)
1111 {
1112 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1113 if (m_bypassPermissions) return m_bypassPermissionsValue;
1114
1115 bool permission = GenericObjectPermission(userID, objectID,false);
1116 if (!permission)
1117 {
1118 if (!m_scene.Entities.ContainsKey(objectID))
1119 {
1120 return false;
1121 }
1122
1123 // If it's not an object, we cant edit it.
1124 if (!(m_scene.Entities[objectID] is SceneObjectGroup))
1125 {
1126 return false;
1127 }
1128
1129 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
1130 // UUID taskOwner = null;
1131 // Added this because at this point in time it wouldn't be wise for
1132 // the administrator object permissions to take effect.
1133 // UUID objectOwner = task.OwnerID;
1134
1135 if ((task.RootPart.EveryoneMask & PERM_COPY) != 0)
1136 permission = true;
1137
1138 if ((task.GetEffectivePermissions() & PERM_COPY) == 0)
1139 permission = false;
1140 }
1141 else
1142 {
1143 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
1144
1145 if ((task.GetEffectivePermissions() & PERM_COPY) == 0)
1146 permission = false;
1147 }
1148
1149 return permission;
1150 }
1151
1152 private bool CanTerraformLand(UUID user, Vector3 position, Scene requestFromScene)
1153 {
1154 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1155 if (m_bypassPermissions) return m_bypassPermissionsValue;
1156
1157 // Estate override
1158 if (GenericEstatePermission(user))
1159 return true;
1160
1161 float X = position.X;
1162 float Y = position.Y;
1163
1164 if (X > 255)
1165 X = 255;
1166 if (Y > 255)
1167 Y = 255;
1168 if (X < 0)
1169 X = 0;
1170 if (Y < 0)
1171 Y = 0;
1172
1173 ILandObject parcel = m_scene.LandChannel.GetLandObject(X, Y);
1174 if (parcel == null)
1175 return false;
1176
1177 // Others allowed to terraform?
1178 if ((parcel.landData.Flags & ((int)Parcel.ParcelFlags.AllowTerraform)) != 0)
1179 return true;
1180
1181 // Land owner can terraform too
1182 if (parcel != null && GenericParcelPermission(user, parcel))
1183 return true;
1184
1185 return false;
1186 }
1187
1188 /// <summary>
1189 /// Check whether the specified user can view the given script
1190 /// </summary>
1191 /// <param name="script"></param>
1192 /// <param name="objectID"></param>
1193 /// <param name="user"></param>
1194 /// <param name="scene"></param>
1195 /// <returns></returns>
1196 private bool CanViewScript(UUID script, UUID objectID, UUID user, Scene scene)
1197 {
1198 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1199 if (m_bypassPermissions) return m_bypassPermissionsValue;
1200
1201 if (objectID == UUID.Zero) // User inventory
1202 {
1203 CachedUserInfo userInfo =
1204 scene.CommsManager.UserProfileCacheService.GetUserDetails(user);
1205
1206 if (userInfo == null)
1207 {
1208 m_log.ErrorFormat("[PERMISSIONS]: Could not find user {0} for administrator check", user);
1209 return false;
1210 }
1211
1212 if (userInfo.RootFolder == null)
1213 return false;
1214
1215 InventoryItemBase assetRequestItem = userInfo.RootFolder.FindItem(script);
1216 if (assetRequestItem == null) // Library item
1217 {
1218 assetRequestItem = m_scene.CommsManager.UserProfileCacheService.LibraryRoot.FindItem(script);
1219
1220 if (assetRequestItem != null) // Implicitly readable
1221 return true;
1222 }
1223
1224 // SL is rather harebrained here. In SL, a script you
1225 // have mod/copy no trans is readable. This subverts
1226 // permissions, but is used in some products, most
1227 // notably Hippo door plugin and HippoRent 5 networked
1228 // prim counter.
1229 // To enable this broken SL-ism, remove Transfer from
1230 // the below expressions.
1231 // Trying to improve on SL perms by making a script
1232 // readable only if it's really full perms
1233 //
1234 if ((assetRequestItem.CurrentPermissions &
1235 ((uint)PermissionMask.Modify |
1236 (uint)PermissionMask.Copy |
1237 (uint)PermissionMask.Transfer)) !=
1238 ((uint)PermissionMask.Modify |
1239 (uint)PermissionMask.Copy |
1240 (uint)PermissionMask.Transfer))
1241 return false;
1242 }
1243 else // Prim inventory
1244 {
1245 SceneObjectPart part = scene.GetSceneObjectPart(objectID);
1246
1247 if (part == null)
1248 return false;
1249
1250 if (part.OwnerID != user)
1251 return false;
1252
1253 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
1254 return false;
1255
1256 TaskInventoryItem ti = part.Inventory.GetInventoryItem(script);
1257
1258 if (ti == null)
1259 return false;
1260
1261 if (ti.OwnerID != user)
1262 return false;
1263
1264 // Require full perms
1265 if ((ti.CurrentPermissions &
1266 ((uint)PermissionMask.Modify |
1267 (uint)PermissionMask.Copy |
1268 (uint)PermissionMask.Transfer)) !=
1269 ((uint)PermissionMask.Modify |
1270 (uint)PermissionMask.Copy |
1271 (uint)PermissionMask.Transfer))
1272 return false;
1273 }
1274
1275 return true;
1276 }
1277
1278 /// <summary>
1279 /// Check whether the specified user can view the given notecard
1280 /// </summary>
1281 /// <param name="script"></param>
1282 /// <param name="objectID"></param>
1283 /// <param name="user"></param>
1284 /// <param name="scene"></param>
1285 /// <returns></returns>
1286 private bool CanViewNotecard(UUID notecard, UUID objectID, UUID user, Scene scene)
1287 {
1288 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1289 if (m_bypassPermissions) return m_bypassPermissionsValue;
1290
1291 if (objectID == UUID.Zero) // User inventory
1292 {
1293 CachedUserInfo userInfo =
1294 scene.CommsManager.UserProfileCacheService.GetUserDetails(user);
1295
1296 if (userInfo == null)
1297 {
1298 m_log.ErrorFormat("[PERMISSIONS]: Could not find user {0} for view notecard check", user);
1299 return false;
1300 }
1301
1302 if (userInfo.RootFolder == null)
1303 return false;
1304
1305 InventoryItemBase assetRequestItem = userInfo.RootFolder.FindItem(notecard);
1306 if (assetRequestItem == null) // Library item
1307 {
1308 assetRequestItem = m_scene.CommsManager.UserProfileCacheService.LibraryRoot.FindItem(notecard);
1309
1310 if (assetRequestItem != null) // Implicitly readable
1311 return true;
1312 }
1313
1314 // Notecards are always readable unless no copy
1315 //
1316 if ((assetRequestItem.CurrentPermissions &
1317 (uint)PermissionMask.Copy) !=
1318 (uint)PermissionMask.Copy)
1319 return false;
1320 }
1321 else // Prim inventory
1322 {
1323 SceneObjectPart part = scene.GetSceneObjectPart(objectID);
1324
1325 if (part == null)
1326 return false;
1327
1328 if (part.OwnerID != user)
1329 return false;
1330
1331 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
1332 return false;
1333
1334 TaskInventoryItem ti = part.Inventory.GetInventoryItem(notecard);
1335
1336 if (ti == null)
1337 return false;
1338
1339 if (ti.OwnerID != user)
1340 return false;
1341
1342 // Notecards are always readable unless no copy
1343 //
1344 if ((ti.CurrentPermissions &
1345 (uint)PermissionMask.Copy) !=
1346 (uint)PermissionMask.Copy)
1347 return false;
1348 }
1349
1350 return true;
1351 }
1352
1353 #endregion
1354
1355 private bool CanLinkObject(UUID userID, UUID objectID)
1356 {
1357 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1358 if (m_bypassPermissions) return m_bypassPermissionsValue;
1359
1360 return true;
1361 }
1362
1363 private bool CanDelinkObject(UUID userID, UUID objectID)
1364 {
1365 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1366 if (m_bypassPermissions) return m_bypassPermissionsValue;
1367
1368 return true;
1369 }
1370
1371 private bool CanBuyLand(UUID userID, ILandObject parcel, Scene scene)
1372 {
1373 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1374 if (m_bypassPermissions) return m_bypassPermissionsValue;
1375
1376 return true;
1377 }
1378
1379 private bool CanCopyObjectInventory(UUID itemID, UUID objectID, UUID userID)
1380 {
1381 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1382 if (m_bypassPermissions) return m_bypassPermissionsValue;
1383
1384 return true;
1385 }
1386
1387 private bool CanDeleteObjectInventory(UUID itemID, UUID objectID, UUID userID)
1388 {
1389 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1390 if (m_bypassPermissions) return m_bypassPermissionsValue;
1391
1392 return true;
1393 }
1394
1395 /// <summary>
1396 /// Check whether the specified user is allowed to directly create the given inventory type in a prim's
1397 /// inventory (e.g. the New Script button in the 1.21 Linden Lab client).
1398 /// </summary>
1399 /// <param name="invType"></param>
1400 /// <param name="objectID"></param>
1401 /// <param name="userID"></param>
1402 /// <returns></returns>
1403 private bool CanCreateObjectInventory(int invType, UUID objectID, UUID userID)
1404 {
1405 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1406 if (m_bypassPermissions) return m_bypassPermissionsValue;
1407
1408 if ((int)InventoryType.LSL == invType)
1409 if (m_allowedScriptCreators == UserSet.Administrators && !IsAdministrator(userID))
1410 return false;
1411
1412 return true;
1413 }
1414
1415 /// <summary>
1416 /// Check whether the specified user is allowed to create the given inventory type in their inventory.
1417 /// </summary>
1418 /// <param name="invType"></param>
1419 /// <param name="userID"></param>
1420 /// <returns></returns>
1421 private bool CanCreateUserInventory(int invType, UUID userID)
1422 {
1423 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1424 if (m_bypassPermissions) return m_bypassPermissionsValue;
1425
1426 if ((int)InventoryType.LSL == invType)
1427 if (m_allowedScriptCreators == UserSet.Administrators && !IsAdministrator(userID))
1428 return false;
1429
1430 return true;
1431 }
1432
1433 /// <summary>
1434 /// Check whether the specified user is allowed to copy the given inventory type in their inventory.
1435 /// </summary>
1436 /// <param name="itemID"></param>
1437 /// <param name="userID"></param>
1438 /// <returns></returns>
1439 private bool CanCopyUserInventory(UUID itemID, UUID userID)
1440 {
1441 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1442 if (m_bypassPermissions) return m_bypassPermissionsValue;
1443
1444 return true;
1445 }
1446
1447 /// <summary>
1448 /// Check whether the specified user is allowed to edit the given inventory item within their own inventory.
1449 /// </summary>
1450 /// <param name="itemID"></param>
1451 /// <param name="userID"></param>
1452 /// <returns></returns>
1453 private bool CanEditUserInventory(UUID itemID, UUID userID)
1454 {
1455 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1456 if (m_bypassPermissions) return m_bypassPermissionsValue;
1457
1458 return true;
1459 }
1460
1461 /// <summary>
1462 /// Check whether the specified user is allowed to delete the given inventory item from their own inventory.
1463 /// </summary>
1464 /// <param name="itemID"></param>
1465 /// <param name="userID"></param>
1466 /// <returns></returns>
1467 private bool CanDeleteUserInventory(UUID itemID, UUID userID)
1468 {
1469 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1470 if (m_bypassPermissions) return m_bypassPermissionsValue;
1471
1472 return true;
1473 }
1474
1475 private bool CanTeleport(UUID userID)
1476 {
1477 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1478 if (m_bypassPermissions) return m_bypassPermissionsValue;
1479
1480 return true;
1481 }
1482
1483 private bool CanResetScript(UUID prim, UUID script, UUID agentID, Scene scene)
1484 {
1485 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1486 if (m_bypassPermissions) return m_bypassPermissionsValue;
1487
1488 SceneObjectPart part = m_scene.GetSceneObjectPart(prim);
1489
1490 // If we selected a sub-prim to reset, prim won't represent the object, but only a part.
1491 // We have to check the permissions of the object, though.
1492 if (part.ParentID != 0) prim = part.ParentUUID;
1493
1494 // You can reset the scripts in any object you can edit
1495 return GenericObjectPermission(agentID, prim, false);
1496 }
1497 }
1498}
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/IFileSerialiser.cs b/OpenSim/Region/CoreModules/World/Serialiser/IFileSerialiser.cs
new file mode 100644
index 0000000..acc7bb8
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Serialiser/IFileSerialiser.cs
@@ -0,0 +1,36 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Scenes;
29
30namespace OpenSim.Region.CoreModules.World.Serialiser
31{
32 internal interface IFileSerialiser
33 {
34 string WriteToFile(Scene scene, string dir);
35 }
36} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
new file mode 100644
index 0000000..ed6448f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
@@ -0,0 +1,125 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using System.IO;
30using System.IO.Compression;
31using System.Text;
32using System.Xml;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.CoreModules.World.Serialiser
36{
37 internal class SerialiseObjects : IFileSerialiser
38 {
39 #region IFileSerialiser Members
40
41 public string WriteToFile(Scene scene, string dir)
42 {
43 string targetFileName = dir + "objects.xml";
44
45 SaveSerialisedToFile(targetFileName, scene);
46
47 return "objects.xml";
48 }
49
50 #endregion
51
52 public void SaveSerialisedToFile(string fileName, Scene scene)
53 {
54 string xmlstream = GetObjectXml(scene);
55
56 MemoryStream stream = ReformatXmlString(xmlstream);
57
58 stream.Seek(0, SeekOrigin.Begin);
59 CreateXmlFile(stream, fileName);
60
61 stream.Seek(0, SeekOrigin.Begin);
62 CreateCompressedXmlFile(stream, fileName);
63 }
64
65 private static MemoryStream ReformatXmlString(string xmlstream)
66 {
67 MemoryStream stream = new MemoryStream();
68 XmlTextWriter formatter = new XmlTextWriter(stream, Encoding.UTF8);
69 XmlDocument doc = new XmlDocument();
70
71 doc.LoadXml(xmlstream);
72 formatter.Formatting = Formatting.Indented;
73 doc.WriteContentTo(formatter);
74 formatter.Flush();
75 return stream;
76 }
77
78 private static string GetObjectXml(Scene scene)
79 {
80 string xmlstream = "<scene>";
81
82 List<EntityBase> EntityList = scene.GetEntities();
83 List<string> EntityXml = new List<string>();
84
85 foreach (EntityBase ent in EntityList)
86 {
87 if (ent is SceneObjectGroup)
88 {
89 EntityXml.Add(((SceneObjectGroup) ent).ToXmlString2());
90 }
91 }
92 EntityXml.Sort();
93
94 foreach (string xml in EntityXml)
95 xmlstream += xml;
96
97 xmlstream += "</scene>";
98 return xmlstream;
99 }
100
101 private static void CreateXmlFile(MemoryStream xmlStream, string fileName)
102 {
103 FileStream objectsFile = new FileStream(fileName, FileMode.Create);
104
105 xmlStream.WriteTo(objectsFile);
106 objectsFile.Flush();
107 objectsFile.Close();
108 }
109
110 private static void CreateCompressedXmlFile(MemoryStream xmlStream, string fileName)
111 {
112 #region GZip Compressed Version
113
114 FileStream objectsFileCompressed = new FileStream(fileName + ".gzs", FileMode.Create);
115 MemoryStream gzipMSStream = new MemoryStream();
116 GZipStream gzipStream = new GZipStream(gzipMSStream, CompressionMode.Compress);
117 xmlStream.WriteTo(gzipStream);
118 gzipMSStream.WriteTo(objectsFileCompressed);
119 objectsFileCompressed.Flush();
120 objectsFileCompressed.Close();
121
122 #endregion
123 }
124 }
125}
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseTerrain.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseTerrain.cs
new file mode 100644
index 0000000..924218a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseTerrain.cs
@@ -0,0 +1,53 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Serialiser
33{
34 internal class SerialiseTerrain : IFileSerialiser
35 {
36 #region IFileSerialiser Members
37
38 public string WriteToFile(Scene scene, string dir)
39 {
40 ITerrainLoader fileSystemExporter = new RAW32();
41 string targetFileName = dir + "heightmap.r32";
42
43 lock (scene.Heightmap)
44 {
45 fileSystemExporter.SaveFile(targetFileName, scene.Heightmap);
46 }
47
48 return "heightmap.r32";
49 }
50
51 #endregion
52 }
53} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs
new file mode 100644
index 0000000..7080d5f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs
@@ -0,0 +1,226 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using OpenMetaverse;
32using Nini.Config;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
36
37namespace OpenSim.Region.CoreModules.World.Serialiser
38{
39 public class SerialiserModule : IRegionModule, IRegionSerialiserModule
40 {
41 private Commander m_commander = new Commander("export");
42 private List<Scene> m_regions = new List<Scene>();
43 private string m_savedir = "exports" + "/";
44 private List<IFileSerialiser> m_serialisers = new List<IFileSerialiser>();
45
46 #region IRegionModule Members
47
48 public void Initialise(Scene scene, IConfigSource source)
49 {
50 scene.RegisterModuleCommander(m_commander);
51 scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
52 scene.RegisterModuleInterface<IRegionSerialiserModule>(this);
53
54 lock (m_regions)
55 {
56 m_regions.Add(scene);
57 }
58 }
59
60 public void PostInitialise()
61 {
62 lock (m_serialisers)
63 {
64 m_serialisers.Add(new SerialiseTerrain());
65 m_serialisers.Add(new SerialiseObjects());
66 }
67
68 LoadCommanderCommands();
69 }
70
71 public void Close()
72 {
73 m_regions.Clear();
74 }
75
76 public string Name
77 {
78 get { return "ExportSerialisationModule"; }
79 }
80
81 public bool IsSharedModule
82 {
83 get { return true; }
84 }
85
86 #endregion
87
88 #region IRegionSerialiser Members
89
90 public void LoadPrimsFromXml(Scene scene, string fileName, bool newIDS, Vector3 loadOffset)
91 {
92 SceneXmlLoader.LoadPrimsFromXml(scene, fileName, newIDS, loadOffset);
93 }
94
95 public void SavePrimsToXml(Scene scene, string fileName)
96 {
97 SceneXmlLoader.SavePrimsToXml(scene, fileName);
98 }
99
100 public void LoadPrimsFromXml2(Scene scene, string fileName)
101 {
102 SceneXmlLoader.LoadPrimsFromXml2(scene, fileName);
103 }
104
105 public void LoadPrimsFromXml2(Scene scene, TextReader reader, bool startScripts)
106 {
107 SceneXmlLoader.LoadPrimsFromXml2(scene, reader, startScripts);
108 }
109
110 public void SavePrimsToXml2(Scene scene, string fileName)
111 {
112 SceneXmlLoader.SavePrimsToXml2(scene, fileName);
113 }
114
115 public void SavePrimsToXml2(Scene scene, TextWriter stream, Vector3 min, Vector3 max)
116 {
117 SceneXmlLoader.SavePrimsToXml2(scene, stream, min, max);
118 }
119
120 public void SaveNamedPrimsToXml2(Scene scene, string primName, string fileName)
121 {
122 SceneXmlLoader.SaveNamedPrimsToXml2(scene, primName, fileName);
123 }
124
125 public SceneObjectGroup DeserializeGroupFromXml2(string xmlString)
126 {
127 return SceneXmlLoader.DeserializeGroupFromXml2(xmlString);
128 }
129
130 public string SaveGroupToXml2(SceneObjectGroup grp)
131 {
132 return SceneXmlLoader.SaveGroupToXml2(grp);
133 }
134
135 public void SavePrimListToXml2(List<EntityBase> entityList, string fileName)
136 {
137 SceneXmlLoader.SavePrimListToXml2(entityList, fileName);
138 }
139
140 public void SavePrimListToXml2(List<EntityBase> entityList, TextWriter stream, Vector3 min, Vector3 max)
141 {
142 SceneXmlLoader.SavePrimListToXml2(entityList, stream, min, max);
143 }
144
145 public List<string> SerialiseRegion(Scene scene, string saveDir)
146 {
147 List<string> results = new List<string>();
148
149 if (!Directory.Exists(saveDir))
150 {
151 Directory.CreateDirectory(saveDir);
152 }
153
154 lock (m_serialisers)
155 {
156 foreach (IFileSerialiser serialiser in m_serialisers)
157 {
158 results.Add(serialiser.WriteToFile(scene, saveDir));
159 }
160 }
161
162 TextWriter regionInfoWriter = new StreamWriter(saveDir + "README.TXT");
163 regionInfoWriter.WriteLine("Region Name: " + scene.RegionInfo.RegionName);
164 regionInfoWriter.WriteLine("Region ID: " + scene.RegionInfo.RegionID.ToString());
165 regionInfoWriter.WriteLine("Backup Time: UTC " + DateTime.UtcNow.ToString());
166 regionInfoWriter.WriteLine("Serialise Version: 0.1");
167 regionInfoWriter.Close();
168
169 TextWriter manifestWriter = new StreamWriter(saveDir + "region.manifest");
170 foreach (string line in results)
171 {
172 manifestWriter.WriteLine(line);
173 }
174 manifestWriter.Close();
175
176 return results;
177 }
178
179 #endregion
180
181 private void EventManager_OnPluginConsole(string[] args)
182 {
183 if (args[0] == "export")
184 {
185 string[] tmpArgs = new string[args.Length - 2];
186 int i = 0;
187 for (i = 2; i < args.Length; i++)
188 tmpArgs[i - 2] = args[i];
189
190 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
191 }
192 }
193
194 private void InterfaceSaveRegion(Object[] args)
195 {
196 foreach (Scene region in m_regions)
197 {
198 if (region.RegionInfo.RegionName == (string) args[0])
199 {
200 // List<string> results = SerialiseRegion(region, m_savedir + region.RegionInfo.RegionID.ToString() + "/");
201 SerialiseRegion(region, m_savedir + region.RegionInfo.RegionID.ToString() + "/");
202 }
203 }
204 }
205
206 private void InterfaceSaveAllRegions(Object[] args)
207 {
208 foreach (Scene region in m_regions)
209 {
210 // List<string> results = SerialiseRegion(region, m_savedir + region.RegionInfo.RegionID.ToString() + "/");
211 SerialiseRegion(region, m_savedir + region.RegionInfo.RegionID.ToString() + "/");
212 }
213 }
214
215 private void LoadCommanderCommands()
216 {
217 Command serialiseSceneCommand = new Command("save", CommandIntentions.COMMAND_NON_HAZARDOUS, InterfaceSaveRegion, "Saves the named region into the exports directory.");
218 serialiseSceneCommand.AddArgument("region-name", "The name of the region you wish to export", "String");
219
220 Command serialiseAllScenesCommand = new Command("save-all",CommandIntentions.COMMAND_NON_HAZARDOUS, InterfaceSaveAllRegions, "Saves all regions into the exports directory.");
221
222 m_commander.RegisterCommand("save", serialiseSceneCommand);
223 m_commander.RegisterCommand("save-all", serialiseAllScenesCommand);
224 }
225 }
226}
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
new file mode 100644
index 0000000..ffd6b8d
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -0,0 +1,97 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using Nini.Config;
31using log4net;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36
37namespace OpenSim.Region.CoreModules.World.Sound
38{
39 public class SoundModule : IRegionModule, ISoundModule
40 {
41 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 protected Scene m_scene;
44
45 public void Initialise(Scene scene, IConfigSource source)
46 {
47 m_scene = scene;
48
49 m_scene.EventManager.OnNewClient += OnNewClient;
50
51 m_scene.RegisterModuleInterface<ISoundModule>(this);
52 }
53
54 public void PostInitialise() {}
55 public void Close() {}
56 public string Name { get { return "Sound Module"; } }
57 public bool IsSharedModule { get { return false; } }
58
59 private void OnNewClient(IClientAPI client)
60 {
61 client.OnSoundTrigger += TriggerSound;
62 }
63
64 public virtual void PlayAttachedSound(
65 UUID soundID, UUID ownerID, UUID objectID, double gain, Vector3 position, byte flags)
66 {
67 foreach (ScenePresence p in m_scene.GetAvatars())
68 {
69 double dis = Util.GetDistanceTo(p.AbsolutePosition, position);
70 if (dis > 100.0) // Max audio distance
71 continue;
72
73 // Scale by distance
74 gain = (float)((double)gain*((100.0 - dis) / 100.0));
75
76 p.ControllingClient.SendPlayAttachedSound(soundID, objectID, ownerID, (float)gain, flags);
77 }
78 }
79
80 public virtual void TriggerSound(
81 UUID soundId, UUID ownerID, UUID objectID, UUID parentID, double gain, Vector3 position, UInt64 handle)
82 {
83 foreach (ScenePresence p in m_scene.GetAvatars())
84 {
85 double dis = Util.GetDistanceTo(p.AbsolutePosition, position);
86 if (dis > 100.0) // Max audio distance
87 continue;
88
89 // Scale by distance
90 gain = (float)((double)gain*((100.0 - dis) / 100.0));
91
92 p.ControllingClient.SendTriggeredSound(
93 soundId, ownerID, objectID, parentID, handle, position, (float)gain);
94 }
95 }
96 }
97}
diff --git a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
new file mode 100644
index 0000000..b36684c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
@@ -0,0 +1,434 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.CoreModules
37{
38 public class SunModule : IRegionModule
39 {
40
41 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
42
43 private const double SeasonalTilt = 0.03 * Math.PI; // A daily shift of approximately 1.7188 degrees
44 private const double AverageTilt = -0.25 * Math.PI; // A 45 degree tilt
45 private const double SunCycle = 2.0D * Math.PI; // A perfect circle measured in radians
46 private const double SeasonalCycle = 2.0D * Math.PI; // Ditto
47
48 //
49 // Per Region Values
50 //
51
52 private bool ready = false;
53
54 // Configurable values
55 private string m_mode = "SL";
56 private int m_frame_mod = 0;
57 private double m_day_length = 0;
58 private int m_year_length = 0;
59 private double m_day_night = 0;
60 // private double m_longitude = 0;
61 // private double m_latitude = 0;
62 // Configurable defaults Defaults close to SL
63 private string d_mode = "SL";
64 private int d_frame_mod = 100; // Every 10 seconds (actually less)
65 private double d_day_length = 4; // A VW day is 4 RW hours long
66 private int d_year_length = 60; // There are 60 VW days in a VW year
67 private double d_day_night = 0.45; // axis offset: ratio of light-to-dark, approx 1:3
68 // private double d_longitude = -73.53;
69 // private double d_latitude = 41.29;
70
71 // Frame counter
72 private uint m_frame = 0;
73
74 // Cached Scene reference
75 private Scene m_scene = null;
76
77 // Calculated Once in the lifetime of a region
78 private long TicksToEpoch; // Elapsed time for 1/1/1970
79 private uint SecondsPerSunCycle; // Length of a virtual day in RW seconds
80 private uint SecondsPerYear; // Length of a virtual year in RW seconds
81 private double SunSpeed; // Rate of passage in radians/second
82 private double SeasonSpeed; // Rate of change for seasonal effects
83 // private double HoursToRadians; // Rate of change for seasonal effects
84 private long TicksOffset = 0; // seconds offset from UTC
85 // Calculated every update
86 private float OrbitalPosition; // Orbital placement at a point in time
87 private double HorizonShift; // Axis offset to skew day and night
88 private double TotalDistanceTravelled; // Distance since beginning of time (in radians)
89 private double SeasonalOffset; // Seaonal variation of tilt
90 private float Magnitude; // Normal tilt
91 // private double VWTimeRatio; // VW time as a ratio of real time
92
93 // Working values
94 private Vector3 Position = Vector3.Zero;
95 private Vector3 Velocity = Vector3.Zero;
96 private Quaternion Tilt = new Quaternion(1.0f, 0.0f, 0.0f, 0.0f);
97
98 private long LindenHourOffset = 0;
99 private bool sunFixed = false;
100
101 private Dictionary<UUID, ulong> m_rootAgents = new Dictionary<UUID, ulong>();
102
103 // Current time in elapsed seconds since Jan 1st 1970
104 private ulong CurrentTime
105 {
106 get {
107 return (ulong)(((System.DateTime.Now.Ticks) - TicksToEpoch + TicksOffset + LindenHourOffset)/10000000);
108 }
109 }
110
111 private float GetLindenEstateHourFromCurrentTime()
112 {
113 float ticksleftover = ((float)CurrentTime) % ((float)SecondsPerSunCycle);
114
115 float hour = (24 * (ticksleftover / SecondsPerSunCycle)) + 6;
116
117 return hour;
118 }
119
120 private void SetTimeByLindenHour(float LindenHour)
121 {
122 // Linden hour is 24 hours with a 6 hour offset. 6-30
123
124 if (LindenHour - 6 == 0)
125 {
126 LindenHourOffset = 0;
127 return;
128 }
129
130 // Remove LindenHourOffset to calculate it from LocalTime
131 float ticksleftover = ((float)(((long)(CurrentTime * 10000000) - (long)LindenHourOffset)/ 10000000) % ((float)SecondsPerSunCycle));
132 float hour = (24 * (ticksleftover / SecondsPerSunCycle));
133
134 float offsethours = 0;
135
136 if (LindenHour - 6 > hour)
137 {
138 offsethours = hour + ((LindenHour-6) - hour);
139 }
140 else
141 {
142 offsethours = hour - (hour - (LindenHour - 6));
143 }
144 //m_log.Debug("[OFFSET]: " + hour + " - " + LindenHour + " - " + offsethours.ToString());
145
146 LindenHourOffset = (long)((float)offsethours * (36000000000/m_day_length));
147 m_log.Debug("[SUN]: Directive from the Estate Tools to set the sun phase to LindenHour " + GetLindenEstateHourFromCurrentTime().ToString());
148 }
149
150 // Called immediately after the module is loaded for a given region
151 // i.e. Immediately after instance creation.
152 public void Initialise(Scene scene, IConfigSource config)
153 {
154 m_scene = scene;
155
156 m_frame = 0;
157
158 TimeZone local = TimeZone.CurrentTimeZone;
159 TicksOffset = local.GetUtcOffset(local.ToLocalTime(DateTime.Now)).Ticks;
160 m_log.Debug("[SUN]: localtime offset is " + TicksOffset);
161
162 // Align ticks with Second Life
163
164 TicksToEpoch = new System.DateTime(1970,1,1).Ticks;
165
166 // Just in case they don't have the stanzas
167 try
168 {
169 // Mode: determines how the sun is handled
170 m_mode = config.Configs["Sun"].GetString("mode", d_mode);
171 // Mode: determines how the sun is handled
172 // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude);
173 // Mode: determines how the sun is handled
174 // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude);
175 // Year length in days
176 m_year_length = config.Configs["Sun"].GetInt("year_length", d_year_length);
177 // Day length in decimal hours
178 m_day_length = config.Configs["Sun"].GetDouble("day_length", d_day_length);
179 // Day to Night Ratio
180 m_day_night = config.Configs["Sun"].GetDouble("day_night_offset", d_day_night);
181 // Update frequency in frames
182 m_frame_mod = config.Configs["Sun"].GetInt("update_interval", d_frame_mod);
183 }
184 catch (Exception e)
185 {
186 m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: "+e.Message);
187 m_mode = d_mode;
188 m_year_length = d_year_length;
189 m_day_length = d_day_length;
190 m_day_night = d_day_night;
191 m_frame_mod = d_frame_mod;
192 // m_latitude = d_latitude;
193 // m_longitude = d_longitude;
194 }
195
196 switch (m_mode)
197 {
198 case "T1":
199 default:
200 case "SL":
201 // Time taken to complete a cycle (day and season)
202
203 SecondsPerSunCycle = (uint) (m_day_length * 60 * 60);
204 SecondsPerYear = (uint) (SecondsPerSunCycle*m_year_length);
205
206 // Ration of real-to-virtual time
207
208 // VWTimeRatio = 24/m_day_length;
209
210 // Speed of rotation needed to complete a cycle in the
211 // designated period (day and season)
212
213 SunSpeed = SunCycle/SecondsPerSunCycle;
214 SeasonSpeed = SeasonalCycle/SecondsPerYear;
215
216 // Horizon translation
217
218 HorizonShift = m_day_night; // Z axis translation
219 // HoursToRadians = (SunCycle/24)*VWTimeRatio;
220
221 // Insert our event handling hooks
222
223 scene.EventManager.OnFrame += SunUpdate;
224 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
225 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
226 scene.EventManager.OnClientClosed += ClientLoggedOut;
227 scene.EventManager.OnEstateToolsTimeUpdate += EstateToolsTimeUpdate;
228 scene.EventManager.OnGetSunLindenHour += GetLindenEstateHourFromCurrentTime;
229
230 ready = true;
231
232 m_log.Debug("[SUN]: Mode is "+m_mode);
233 m_log.Debug("[SUN]: Initialization completed. Day is "+SecondsPerSunCycle+" seconds, and year is "+m_year_length+" days");
234 m_log.Debug("[SUN]: Axis offset is "+m_day_night);
235 m_log.Debug("[SUN]: Positional data updated every "+m_frame_mod+" frames");
236
237 break;
238 }
239 }
240
241 public void PostInitialise()
242 {
243 }
244
245 public void Close()
246 {
247 ready = false;
248
249 // Remove our hooks
250 m_scene.EventManager.OnFrame -= SunUpdate;
251 m_scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
252 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel;
253 m_scene.EventManager.OnClientClosed -= ClientLoggedOut;
254 m_scene.EventManager.OnEstateToolsTimeUpdate -= EstateToolsTimeUpdate;
255 m_scene.EventManager.OnGetSunLindenHour -= GetLindenEstateHourFromCurrentTime;
256 }
257
258 public string Name
259 {
260 get { return "SunModule"; }
261 }
262
263 public bool IsSharedModule
264 {
265 get { return false; }
266 }
267
268 public void SunToClient(IClientAPI client)
269 {
270 if (m_mode != "T1")
271 {
272 if (ready)
273 {
274 if (!sunFixed)
275 GenSunPos(); // Generate shared values once
276 client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
277 }
278 }
279 }
280
281 public void SunUpdate()
282 {
283 if (((m_frame++%m_frame_mod) != 0) || !ready || sunFixed)
284 {
285 return;
286 }
287
288 GenSunPos(); // Generate shared values once
289
290 List<ScenePresence> avatars = m_scene.GetAvatars();
291 foreach (ScenePresence avatar in avatars)
292 {
293 if (!avatar.IsChildAgent)
294 avatar.ControllingClient.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
295 }
296
297 // set estate settings for region access to sun position
298 m_scene.RegionInfo.RegionSettings.SunVector = Position;
299 //m_scene.RegionInfo.EstateSettings.sunHour = GetLindenEstateHourFromCurrentTime();
300 }
301
302 public void ForceSunUpdateToAllClients()
303 {
304 GenSunPos(); // Generate shared values once
305
306 List<ScenePresence> avatars = m_scene.GetAvatars();
307 foreach (ScenePresence avatar in avatars)
308 {
309 if (!avatar.IsChildAgent)
310 avatar.ControllingClient.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
311 }
312
313 // set estate settings for region access to sun position
314 m_scene.RegionInfo.RegionSettings.SunVector = Position;
315 m_scene.RegionInfo.RegionSettings.SunPosition = GetLindenEstateHourFromCurrentTime();
316 }
317
318 /// <summary>
319 /// Calculate the sun's orbital position and its velocity.
320 /// </summary>
321 private void GenSunPos()
322 {
323 TotalDistanceTravelled = SunSpeed * CurrentTime; // distance measured in radians
324 OrbitalPosition = (float) (TotalDistanceTravelled%SunCycle); // position measured in radians
325
326 // TotalDistanceTravelled += HoursToRadians-(0.25*Math.PI)*Math.Cos(HoursToRadians)-OrbitalPosition;
327 // OrbitalPosition = (float) (TotalDistanceTravelled%SunCycle);
328
329 SeasonalOffset = SeasonSpeed * CurrentTime; // Present season determined as total radians travelled around season cycle
330
331 Tilt.W = (float) (AverageTilt + (SeasonalTilt*Math.Sin(SeasonalOffset))); // Calculate seasonal orbital N/S tilt
332
333 // m_log.Debug("[SUN] Total distance travelled = "+TotalDistanceTravelled+", present position = "+OrbitalPosition+".");
334 // m_log.Debug("[SUN] Total seasonal progress = "+SeasonalOffset+", present tilt = "+Tilt.W+".");
335
336 // The sun rotates about the Z axis
337
338 Position.X = (float) Math.Cos(-TotalDistanceTravelled);
339 Position.Y = (float) Math.Sin(-TotalDistanceTravelled);
340 Position.Z = 0;
341
342 // For interest we rotate it slightly about the X access.
343 // Celestial tilt is a value that ranges .025
344
345 Position *= Tilt;
346
347 // Finally we shift the axis so that more of the
348 // circle is above the horizon than below. This
349 // makes the nights shorter than the days.
350
351 Position.Z = Position.Z + (float) HorizonShift;
352 Position = Vector3.Normalize(Position);
353
354 // m_log.Debug("[SUN] Position("+Position.X+","+Position.Y+","+Position.Z+")");
355
356 Velocity.X = 0;
357 Velocity.Y = 0;
358 Velocity.Z = (float) SunSpeed;
359
360 // Correct angular velocity to reflect the seasonal rotation
361
362 Magnitude = Position.Length();
363 if (sunFixed)
364 {
365 Velocity.X = 0;
366 Velocity.Y = 0;
367 Velocity.Z = 0;
368 return;
369 }
370
371 Velocity = (Velocity * Tilt) * (1.0f / Magnitude);
372
373 // m_log.Debug("[SUN] Velocity("+Velocity.X+","+Velocity.Y+","+Velocity.Z+")");
374 }
375
376 private void ClientLoggedOut(UUID AgentId)
377 {
378 lock (m_rootAgents)
379 {
380 if (m_rootAgents.ContainsKey(AgentId))
381 {
382 m_rootAgents.Remove(AgentId);
383 }
384 }
385 }
386
387 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
388 {
389 lock (m_rootAgents)
390 {
391 if (m_rootAgents.ContainsKey(avatar.UUID))
392 {
393 m_rootAgents[avatar.UUID] = avatar.RegionHandle;
394 }
395 else
396 {
397 m_rootAgents.Add(avatar.UUID, avatar.RegionHandle);
398 SunToClient(avatar.ControllingClient);
399 }
400 }
401 //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString());
402 }
403
404 private void MakeChildAgent(ScenePresence avatar)
405 {
406 lock (m_rootAgents)
407 {
408 if (m_rootAgents.ContainsKey(avatar.UUID))
409 {
410 if (m_rootAgents[avatar.UUID] == avatar.RegionHandle)
411 {
412 m_rootAgents.Remove(avatar.UUID);
413 }
414 }
415 }
416 }
417
418 public void EstateToolsTimeUpdate(ulong regionHandle, bool FixedTime, bool useEstateTime, float LindenHour)
419 {
420 if (m_scene.RegionInfo.RegionHandle == regionHandle)
421 {
422 SetTimeByLindenHour(LindenHour);
423
424 //if (useEstateTime)
425 //LindenHourOffset = 0;
426
427 ForceSunUpdateToAllClients();
428 sunFixed = FixedTime;
429 if (sunFixed)
430 GenSunPos();
431 }
432 }
433 }
434}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/DefaultEffects/ChannelDigger.cs b/OpenSim/Region/CoreModules/World/Terrain/DefaultEffects/ChannelDigger.cs
new file mode 100644
index 0000000..f96ab88
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/DefaultEffects/ChannelDigger.cs
@@ -0,0 +1,107 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.CoreModules.World.Terrain;
31using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes;
32
33namespace OpenSim.Region.Modules.Terrain.Extensions.DefaultEffects.Effects
34{
35 public class ChannelDigger : ITerrainEffect
36 {
37 private readonly int num_h = 4;
38 private readonly int num_w = 4;
39
40 private readonly ITerrainFloodEffect raiseFunction = new RaiseArea();
41 private readonly ITerrainFloodEffect smoothFunction = new SmoothArea();
42
43 #region ITerrainEffect Members
44
45 public void RunEffect(ITerrainChannel map)
46 {
47 FillMap(map, 15);
48 BuildTiles(map, 7);
49 SmoothMap(map, 3);
50 }
51
52 #endregion
53
54 private void SmoothMap(ITerrainChannel map, int rounds)
55 {
56 Boolean[,] bitmap = new bool[map.Width,map.Height];
57 for (int x = 0; x < map.Width; x++)
58 {
59 for (int y = 0; y < map.Height; y++)
60 {
61 bitmap[x, y] = true;
62 }
63 }
64
65 for (int i = 0; i < rounds; i++)
66 {
67 smoothFunction.FloodEffect(map, bitmap, 1.0);
68 }
69 }
70
71 private void FillMap(ITerrainChannel map, double val)
72 {
73 for (int x = 0; x < map.Width; x++)
74 for (int y = 0; y < map.Height; y++)
75 map[x, y] = val;
76 }
77
78 private void BuildTiles(ITerrainChannel map, double height)
79 {
80 int channelWidth = (int) Math.Floor((map.Width / num_w) * 0.8);
81 int channelHeight = (int) Math.Floor((map.Height / num_h) * 0.8);
82 int channelXOffset = (map.Width / num_w) - channelWidth;
83 int channelYOffset = (map.Height / num_h) - channelHeight;
84
85 for (int x = 0; x < num_w; x++)
86 {
87 for (int y = 0; y < num_h; y++)
88 {
89 int xoff = ((channelXOffset + channelWidth) * x) + (channelXOffset / 2);
90 int yoff = ((channelYOffset + channelHeight) * y) + (channelYOffset / 2);
91
92 Boolean[,] bitmap = new bool[map.Width,map.Height];
93
94 for (int dx = 0; dx < channelWidth; dx++)
95 {
96 for (int dy = 0; dy < channelHeight; dy++)
97 {
98 bitmap[dx + xoff, dy + yoff] = true;
99 }
100 }
101
102 raiseFunction.FloodEffect(map, bitmap, height);
103 }
104 }
105 }
106 }
107}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs
new file mode 100644
index 0000000..cb8112c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs
@@ -0,0 +1,125 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenSim.Region.Framework.Interfaces;
29using OpenSim.Region.Framework.Scenes;
30using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.Effects
33{
34 internal class CookieCutter : ITerrainEffect
35 {
36 #region ITerrainEffect Members
37
38 public void RunEffect(ITerrainChannel map)
39 {
40 ITerrainPaintableEffect eroder = new WeatherSphere();
41
42 bool[,] cliffMask = new bool[map.Width,map.Height];
43 bool[,] channelMask = new bool[map.Width,map.Height];
44 bool[,] smoothMask = new bool[map.Width,map.Height];
45 bool[,] allowMask = new bool[map.Width,map.Height];
46
47 Console.WriteLine("S1");
48
49 // Step one, generate rough mask
50 int x, y;
51 for (x = 0; x < map.Width; x++)
52 {
53 for (y = 0; y < map.Height; y++)
54 {
55 Console.Write(".");
56 smoothMask[x, y] = true;
57 allowMask[x,y] = true;
58
59 // Start underwater
60 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 5;
61 // Add a little height. (terrain should now be above water, mostly.)
62 map[x, y] += 20;
63
64 const int channelsX = 4;
65 int channelWidth = (map.Width / channelsX / 4);
66 const int channelsY = 4;
67 int channelHeight = (map.Height / channelsY / 4);
68
69 SetLowerChannel(map, cliffMask, channelMask, x, y, channelsX, channelWidth, map.Width, x);
70 SetLowerChannel(map, cliffMask, channelMask, x, y, channelsY, channelHeight, map.Height, y);
71 }
72 }
73
74 Console.WriteLine("S2");
75 //smooth.FloodEffect(map, smoothMask, 4.0);
76
77 Console.WriteLine("S3");
78 for (x = 0; x < map.Width; x++)
79 {
80 for (y = 0; y < map.Height; y++)
81 {
82 if (cliffMask[x, y])
83 eroder.PaintEffect(map, allowMask, x, y, -1, 4, 0.1);
84 }
85 }
86
87 for (x = 0; x < map.Width; x += 2)
88 {
89 for (y = 0; y < map.Height; y += 2)
90 {
91 if (map[x, y] < 0.1)
92 map[x, y] = 0.1;
93 if (map[x, y] > 256)
94 map[x, y] = 256;
95 }
96 }
97 //smooth.FloodEffect(map, smoothMask, 4.0);
98 }
99
100 #endregion
101
102 private static void SetLowerChannel(ITerrainChannel map, bool[,] cliffMask, bool[,] channelMask, int x, int y, int numChannels, int channelWidth,
103 int mapSize, int rp)
104 {
105 for (int i = 0; i < numChannels; i++)
106 {
107 double distanceToLine = Math.Abs(rp - ((mapSize / numChannels) * i));
108
109 if (distanceToLine < channelWidth)
110 {
111 if (channelMask[x, y])
112 return;
113
114 // Remove channels
115 map[x, y] -= 10;
116 channelMask[x, y] = true;
117 }
118 if (distanceToLine < 1)
119 {
120 cliffMask[x, y] = true;
121 }
122 }
123 }
124 }
125}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
new file mode 100644
index 0000000..da6ee12
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
@@ -0,0 +1,56 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using OpenSim.Framework;
28using OpenSim.Region.Framework.Interfaces;
29using OpenSim.Region.Framework.Scenes;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Effects
32{
33 internal class DefaultTerrainGenerator : ITerrainEffect
34 {
35 #region ITerrainEffect Members
36
37 public void RunEffect(ITerrainChannel map)
38 {
39 int x, y;
40 for (x = 0; x < map.Width; x++)
41 {
42 for (y = 0; y < map.Height; y++)
43 {
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;
46 if (map[x, y] < spherFac)
47 {
48 map[x, y] = spherFac;
49 }
50 }
51 }
52 }
53
54 #endregion
55 }
56} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs
new file mode 100644
index 0000000..4f395b5
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs
@@ -0,0 +1,76 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Drawing;
29using System.Drawing.Imaging;
30using System.IO;
31using OpenSim.Region.Framework.Interfaces;
32
33namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
34{
35 /// <summary>
36 /// A generic windows bitmap loader.
37 /// Should be capable of handling 24-bit RGB images.
38 ///
39 /// Uses the System.Drawing filesystem loader.
40 /// </summary>
41 internal class BMP : GenericSystemDrawing
42 {
43 /// <summary>
44 /// Exports a file to a image on the disk using a System.Drawing exporter.
45 /// </summary>
46 /// <param name="filename">The target filename</param>
47 /// <param name="map">The terrain channel being saved</param>
48 public override void SaveFile(string filename, ITerrainChannel map)
49 {
50 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
51
52 colours.Save(filename, ImageFormat.Bmp);
53 }
54
55 /// <summary>
56 /// Exports a stream using a System.Drawing exporter.
57 /// </summary>
58 /// <param name="stream">The target stream</param>
59 /// <param name="map">The terrain channel being saved</param>
60 public override void SaveStream(Stream stream, ITerrainChannel map)
61 {
62 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
63
64 colours.Save(stream, ImageFormat.Png);
65 }
66
67 /// <summary>
68 /// The human readable version of the file format(s) this loader handles
69 /// </summary>
70 /// <returns></returns>
71 public override string ToString()
72 {
73 return "BMP";
74 }
75 }
76}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs
new file mode 100644
index 0000000..cff82d1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs
@@ -0,0 +1,61 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Drawing;
29using System.Drawing.Imaging;
30using System.IO;
31using OpenSim.Region.Framework.Interfaces;
32
33namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
34{
35 internal class GIF : GenericSystemDrawing
36 {
37 public override void SaveFile(string filename, ITerrainChannel map)
38 {
39 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
40
41 colours.Save(filename, ImageFormat.Gif);
42 }
43
44 /// <summary>
45 /// Exports a stream using a System.Drawing exporter.
46 /// </summary>
47 /// <param name="stream">The target stream</param>
48 /// <param name="map">The terrain channel being saved</param>
49 public override void SaveStream(Stream stream, ITerrainChannel map)
50 {
51 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
52
53 colours.Save(stream, ImageFormat.Gif);
54 }
55
56 public override string ToString()
57 {
58 return "GIF";
59 }
60 }
61}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
new file mode 100644
index 0000000..477c73c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
@@ -0,0 +1,195 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Drawing;
30using System.Drawing.Imaging;
31using System.IO;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
36{
37 /// <summary>
38 /// A virtual class designed to have methods overloaded,
39 /// this class provides an interface for a generic image
40 /// saving and loading mechanism, but does not specify the
41 /// format. It should not be insubstantiated directly.
42 /// </summary>
43 public class GenericSystemDrawing : ITerrainLoader
44 {
45 #region ITerrainLoader Members
46
47 public string FileExtension
48 {
49 get { return ".gsd"; }
50 }
51
52 /// <summary>
53 /// Loads a file from a specified filename on the disk,
54 /// parses the image using the System.Drawing parsers
55 /// then returns a terrain channel. Values are
56 /// returned based on HSL brightness between 0m and 128m
57 /// </summary>
58 /// <param name="filename">The target image to load</param>
59 /// <returns>A terrain channel generated from the image.</returns>
60 public virtual ITerrainChannel LoadFile(string filename)
61 {
62 return LoadBitmap(new Bitmap(filename));
63 }
64
65 public ITerrainChannel LoadFile(string filename, int x, int y, int fileWidth, int fileHeight, int w, int h)
66 {
67 throw new NotImplementedException();
68 }
69
70 public virtual ITerrainChannel LoadStream(Stream stream)
71 {
72 return LoadBitmap(new Bitmap(stream));
73 }
74
75 protected virtual ITerrainChannel LoadBitmap(Bitmap bitmap)
76 {
77 ITerrainChannel retval = new TerrainChannel(bitmap.Width, bitmap.Height);
78
79 int x;
80 for (x = 0; x < bitmap.Width; x++)
81 {
82 int y;
83 for (y = 0; y < bitmap.Height; y++)
84 {
85 retval[x, y] = bitmap.GetPixel(x, bitmap.Height - y - 1).GetBrightness() * 128;
86 }
87 }
88
89 return retval;
90 }
91
92 /// <summary>
93 /// Exports a file to a image on the disk using a System.Drawing exporter.
94 /// </summary>
95 /// <param name="filename">The target filename</param>
96 /// <param name="map">The terrain channel being saved</param>
97 public virtual void SaveFile(string filename, ITerrainChannel map)
98 {
99 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
100
101 colours.Save(filename, ImageFormat.Png);
102 }
103
104 /// <summary>
105 /// Exports a stream using a System.Drawing exporter.
106 /// </summary>
107 /// <param name="stream">The target stream</param>
108 /// <param name="map">The terrain channel being saved</param>
109 public virtual void SaveStream(Stream stream, ITerrainChannel map)
110 {
111 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
112
113 colours.Save(stream, ImageFormat.Png);
114 }
115
116 #endregion
117
118 public override string ToString()
119 {
120 return "SYS.DRAWING";
121 }
122
123 /// <summary>
124 /// Protected method, generates a grayscale bitmap
125 /// image from a specified terrain channel.
126 /// </summary>
127 /// <param name="map">The terrain channel to export to bitmap</param>
128 /// <returns>A System.Drawing.Bitmap containing a grayscale image</returns>
129 protected static Bitmap CreateGrayscaleBitmapFromMap(ITerrainChannel map)
130 {
131 Bitmap bmp = new Bitmap(map.Width, map.Height);
132
133 const int pallete = 256;
134
135 Color[] grays = new Color[pallete];
136 for (int i = 0; i < grays.Length; i++)
137 {
138 grays[i] = Color.FromArgb(i, i, i);
139 }
140
141 for (int y = 0; y < map.Height; y++)
142 {
143 for (int x = 0; x < map.Width; x++)
144 {
145 // 512 is the largest possible height before colours clamp
146 int colorindex = (int) (Math.Max(Math.Min(1.0, map[x, y] / 128.0), 0.0) * (pallete - 1));
147
148 // Handle error conditions
149 if (colorindex > pallete - 1 || colorindex < 0)
150 bmp.SetPixel(x, map.Height - y - 1, Color.Red);
151 else
152 bmp.SetPixel(x, map.Height - y - 1, grays[colorindex]);
153 }
154 }
155 return bmp;
156 }
157
158 /// <summary>
159 /// Protected method, generates a coloured bitmap
160 /// image from a specified terrain channel.
161 /// </summary>
162 /// <param name="map">The terrain channel to export to bitmap</param>
163 /// <returns>A System.Drawing.Bitmap containing a coloured image</returns>
164 protected static Bitmap CreateBitmapFromMap(ITerrainChannel map)
165 {
166 Bitmap gradientmapLd = new Bitmap("defaultstripe.png");
167
168 int pallete = gradientmapLd.Height;
169
170 Bitmap bmp = new Bitmap(map.Width, map.Height);
171 Color[] colours = new Color[pallete];
172
173 for (int i = 0; i < pallete; i++)
174 {
175 colours[i] = gradientmapLd.GetPixel(0, i);
176 }
177
178 for (int y = 0; y < map.Height; y++)
179 {
180 for (int x = 0; x < map.Width; x++)
181 {
182 // 512 is the largest possible height before colours clamp
183 int colorindex = (int) (Math.Max(Math.Min(1.0, map[x, y] / 512.0), 0.0) * (pallete - 1));
184
185 // Handle error conditions
186 if (colorindex > pallete - 1 || colorindex < 0)
187 bmp.SetPixel(x, map.Height - y - 1, Color.Red);
188 else
189 bmp.SetPixel(x, map.Height - y - 1, colours[colorindex]);
190 }
191 }
192 return bmp;
193 }
194 }
195}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs
new file mode 100644
index 0000000..f8e31f8
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs
@@ -0,0 +1,112 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Drawing;
30using System.Drawing.Imaging;
31using System.IO;
32using OpenSim.Region.Framework.Interfaces;
33
34namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
35{
36 public class JPEG : ITerrainLoader
37 {
38 #region ITerrainLoader Members
39
40 public string FileExtension
41 {
42 get { return ".jpg"; }
43 }
44
45 public ITerrainChannel LoadFile(string filename)
46 {
47 throw new NotImplementedException();
48 }
49
50 public ITerrainChannel LoadFile(string filename, int x, int y, int fileWidth, int fileHeight, int w, int h)
51 {
52 throw new NotImplementedException();
53 }
54
55 public ITerrainChannel LoadStream(Stream stream)
56 {
57 throw new NotImplementedException();
58 }
59
60 public void SaveFile(string filename, ITerrainChannel map)
61 {
62 Bitmap colours = CreateBitmapFromMap(map);
63
64 colours.Save(filename, ImageFormat.Jpeg);
65 }
66
67 /// <summary>
68 /// Exports a stream using a System.Drawing exporter.
69 /// </summary>
70 /// <param name="stream">The target stream</param>
71 /// <param name="map">The terrain channel being saved</param>
72 public void SaveStream(Stream stream, ITerrainChannel map)
73 {
74 Bitmap colours = CreateBitmapFromMap(map);
75
76 colours.Save(stream, ImageFormat.Jpeg);
77 }
78
79 #endregion
80
81 public override string ToString()
82 {
83 return "JPEG";
84 }
85
86 private static Bitmap CreateBitmapFromMap(ITerrainChannel map)
87 {
88 Bitmap gradientmapLd = new Bitmap("defaultstripe.png");
89
90 int pallete = gradientmapLd.Height;
91
92 Bitmap bmp = new Bitmap(map.Width, map.Height);
93 Color[] colours = new Color[pallete];
94
95 for (int i = 0; i < pallete; i++)
96 {
97 colours[i] = gradientmapLd.GetPixel(0, i);
98 }
99
100 for (int y = 0; y < map.Height; y++)
101 {
102 for (int x = 0; x < map.Width; x++)
103 {
104 // 512 is the largest possible height before colours clamp
105 int colorindex = (int) (Math.Max(Math.Min(1.0, map[x, y] / 512.0), 0.0) * (pallete - 1));
106 bmp.SetPixel(x, map.Height - y - 1, colours[colorindex]);
107 }
108 }
109 return bmp;
110 }
111 }
112}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
new file mode 100644
index 0000000..a86ae00
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
@@ -0,0 +1,250 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using OpenSim.Region.Framework.Interfaces;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
34{
35 public class LLRAW : ITerrainLoader
36 {
37 public struct HeightmapLookupValue : IComparable<HeightmapLookupValue>
38 {
39 public int Index;
40 public double Value;
41
42 public HeightmapLookupValue(int index, double value)
43 {
44 Index = index;
45 Value = value;
46 }
47
48 public int CompareTo(HeightmapLookupValue val)
49 {
50 return Value.CompareTo(val.Value);
51 }
52 }
53
54 /// <summary>Lookup table to speed up terrain exports</summary>
55 HeightmapLookupValue[] LookupHeightTable;
56
57 public LLRAW()
58 {
59 LookupHeightTable = new HeightmapLookupValue[256 * 256];
60
61 for (int i = 0; i < 256; i++)
62 {
63 for (int j = 0; j < 256; j++)
64 {
65 LookupHeightTable[i + (j * 256)] = new HeightmapLookupValue(i + (j * 256), ((double)i * ((double)j / 128.0d)));
66 }
67 }
68 Array.Sort<HeightmapLookupValue>(LookupHeightTable);
69 }
70
71 #region ITerrainLoader Members
72
73 public ITerrainChannel LoadFile(string filename)
74 {
75 FileInfo file = new FileInfo(filename);
76 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
77 ITerrainChannel retval = LoadStream(s);
78
79 s.Close();
80
81 return retval;
82 }
83
84 public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight)
85 {
86 TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight);
87
88 FileInfo file = new FileInfo(filename);
89 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
90 BinaryReader bs = new BinaryReader(s);
91
92 int currFileYOffset = fileHeight - 1;
93
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 {
98 // read a whole strip of regions
99 int heightsToRead = sectionHeight * (fileWidth * sectionWidth);
100 bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels
101 currFileYOffset--;
102 }
103
104 // got to the Y start offset within the file of our region
105 // so read the file bits associated with our region
106 int y;
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 {
117 bs.ReadBytes(sectionWidth * 13);
118 currFileXOffset++;
119 }
120
121 // got to our X offset, so write our regions X line
122 int x;
123 for (x = 0; x < sectionWidth; x++)
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
132 // if our region isn't the last X section of the areas to be landscaped, then
133 // advance the stream to the end of this Y column
134 while (currFileXOffset < fileWidth)
135 {
136 // eat the next regions x line
137 bs.ReadBytes(sectionWidth * 13); //The 13 channels again
138 currFileXOffset++;
139 }
140 }
141
142 bs.Close();
143 s.Close();
144
145 return retval;
146 }
147
148 public ITerrainChannel LoadStream(Stream s)
149 {
150 TerrainChannel retval = new TerrainChannel();
151
152 BinaryReader bs = new BinaryReader(s);
153 int y;
154 for (y = 0; y < retval.Height; y++)
155 {
156 int x;
157 for (x = 0; x < retval.Width; x++)
158 {
159 retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
160 bs.ReadBytes(11); // Advance the stream to next bytes.
161 }
162 }
163
164 bs.Close();
165
166 return retval;
167 }
168
169 public void SaveFile(string filename, ITerrainChannel map)
170 {
171 FileInfo file = new FileInfo(filename);
172 FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write);
173 SaveStream(s, map);
174
175 s.Close();
176 }
177
178 public void SaveStream(Stream s, ITerrainChannel map)
179 {
180 BinaryWriter binStream = new BinaryWriter(s);
181
182 // Output the calculated raw
183 for (int y = 0; y < map.Height; y++)
184 {
185 for (int x = 0; x < map.Width; x++)
186 {
187 double t = map[x, (map.Height - 1) - y];
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 {
192 t = 0d;
193 }
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, 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 }
233 }
234
235 binStream.Close();
236 }
237
238 public string FileExtension
239 {
240 get { return ".raw"; }
241 }
242
243 #endregion
244
245 public override string ToString()
246 {
247 return "LL/SL RAW";
248 }
249 }
250}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs
new file mode 100644
index 0000000..0dea282
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs
@@ -0,0 +1,61 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Drawing;
29using System.Drawing.Imaging;
30using System.IO;
31using OpenSim.Region.Framework.Interfaces;
32
33namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
34{
35 internal class PNG : GenericSystemDrawing
36 {
37 public override void SaveFile(string filename, ITerrainChannel map)
38 {
39 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
40
41 colours.Save(filename, ImageFormat.Png);
42 }
43
44 /// <summary>
45 /// Exports a stream using a System.Drawing exporter.
46 /// </summary>
47 /// <param name="stream">The target stream</param>
48 /// <param name="map">The terrain channel being saved</param>
49 public override void SaveStream(Stream stream, ITerrainChannel map)
50 {
51 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
52
53 colours.Save(stream, ImageFormat.Png);
54 }
55
56 public override string ToString()
57 {
58 return "PNG";
59 }
60 }
61}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
new file mode 100644
index 0000000..178104f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
@@ -0,0 +1,170 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.IO;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
33{
34 public class RAW32 : ITerrainLoader
35 {
36 #region ITerrainLoader Members
37
38 public string FileExtension
39 {
40 get { return ".r32"; }
41 }
42
43 public ITerrainChannel LoadFile(string filename)
44 {
45 FileInfo file = new FileInfo(filename);
46 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
47 ITerrainChannel retval = LoadStream(s);
48
49 s.Close();
50
51 return retval;
52 }
53
54 public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight)
55 {
56 TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight);
57
58 FileInfo file = new FileInfo(filename);
59 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
60 BinaryReader bs = new BinaryReader(s);
61
62 int currFileYOffset = 0;
63
64 // if our region isn't on the first Y section of the areas to be landscaped, then
65 // advance to our section of the file
66 while (currFileYOffset < offsetY)
67 {
68 // read a whole strip of regions
69 int heightsToRead = sectionHeight * (fileWidth * sectionWidth);
70 bs.ReadBytes(heightsToRead * 4); // because the floats are 4 bytes in the file
71 currFileYOffset++;
72 }
73
74 // got to the Y start offset within the file of our region
75 // so read the file bits associated with our region
76 int y;
77 // for each Y within our Y offset
78 for (y = 0; y < sectionHeight; y++)
79 {
80 int currFileXOffset = 0;
81
82 // if our region isn't the first X section of the areas to be landscaped, then
83 // advance the stream to the X start pos of our section in the file
84 // i.e. eat X upto where we start
85 while (currFileXOffset < offsetX)
86 {
87 bs.ReadBytes(sectionWidth * 4); // 4 bytes = single
88 currFileXOffset++;
89 }
90
91 // got to our X offset, so write our regions X line
92 int x;
93 for (x = 0; x < sectionWidth; x++)
94 {
95 // Read a strip and continue
96 retval[x, y] = bs.ReadSingle();
97 }
98 // record that we wrote it
99 currFileXOffset++;
100
101 // if our region isn't the last X section of the areas to be landscaped, then
102 // advance the stream to the end of this Y column
103 while (currFileXOffset < fileWidth)
104 {
105 // eat the next regions x line
106 bs.ReadBytes(sectionWidth * 4); // 4 bytes = single
107 currFileXOffset++;
108 }
109 }
110
111 bs.Close();
112 s.Close();
113
114 return retval;
115 }
116
117 public ITerrainChannel LoadStream(Stream s)
118 {
119 TerrainChannel retval = new TerrainChannel();
120
121 BinaryReader bs = new BinaryReader(s);
122 int y;
123 for (y = 0; y < retval.Height; y++)
124 {
125 int x;
126 for (x = 0; x < retval.Width; x++)
127 {
128 retval[x, y] = bs.ReadSingle();
129 }
130 }
131
132 bs.Close();
133
134 return retval;
135 }
136
137 public void SaveFile(string filename, ITerrainChannel map)
138 {
139 FileInfo file = new FileInfo(filename);
140 FileStream s = file.Open(FileMode.Create, FileAccess.Write);
141 SaveStream(s, map);
142
143 s.Close();
144 }
145
146 public void SaveStream(Stream s, ITerrainChannel map)
147 {
148 BinaryWriter bs = new BinaryWriter(s);
149
150 int y;
151 for (y = 0; y < map.Height; y++)
152 {
153 int x;
154 for (x = 0; x < map.Width; x++)
155 {
156 bs.Write((float) map[x, y]);
157 }
158 }
159
160 bs.Close();
161 }
162
163 #endregion
164
165 public override string ToString()
166 {
167 return "RAW32";
168 }
169 }
170}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs
new file mode 100644
index 0000000..220431f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs
@@ -0,0 +1,61 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Drawing;
29using System.Drawing.Imaging;
30using System.IO;
31using OpenSim.Region.Framework.Interfaces;
32
33namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
34{
35 internal class TIFF : GenericSystemDrawing
36 {
37 public override void SaveFile(string filename, ITerrainChannel map)
38 {
39 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
40
41 colours.Save(filename, ImageFormat.Tiff);
42 }
43
44 /// <summary>
45 /// Exports a stream using a System.Drawing exporter.
46 /// </summary>
47 /// <param name="stream">The target stream</param>
48 /// <param name="map">The terrain channel being saved</param>
49 public override void SaveStream(Stream stream, ITerrainChannel map)
50 {
51 Bitmap colours = CreateGrayscaleBitmapFromMap(map);
52
53 colours.Save(stream, ImageFormat.Tiff);
54 }
55
56 public override string ToString()
57 {
58 return "TIFF";
59 }
60 }
61}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
new file mode 100644
index 0000000..426708d
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
@@ -0,0 +1,142 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Text;
31using OpenSim.Region.Framework.Interfaces;
32using OpenSim.Region.Framework.Scenes;
33
34namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
35{
36 /// <summary>
37 /// Terragen File Format Loader
38 /// Built from specification at
39 /// http://www.planetside.co.uk/terragen/dev/tgterrain.html
40 /// </summary>
41 internal class Terragen : ITerrainLoader
42 {
43 #region ITerrainLoader Members
44
45 public ITerrainChannel LoadFile(string filename)
46 {
47 FileInfo file = new FileInfo(filename);
48 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
49 ITerrainChannel retval = LoadStream(s);
50
51 s.Close();
52
53 return retval;
54 }
55
56 public ITerrainChannel LoadStream(Stream s)
57 {
58 TerrainChannel retval = new TerrainChannel();
59
60 BinaryReader bs = new BinaryReader(s);
61
62 bool eof = false;
63 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ")
64 {
65 int w = 256;
66 int h = 256;
67
68 // Terragen file
69 while (eof == false)
70 {
71 string tmp = Encoding.ASCII.GetString(bs.ReadBytes(4));
72 switch (tmp)
73 {
74 case "SIZE":
75 int sztmp = bs.ReadInt16() + 1;
76 w = sztmp;
77 h = sztmp;
78 bs.ReadInt16();
79 break;
80 case "XPTS":
81 w = bs.ReadInt16();
82 bs.ReadInt16();
83 break;
84 case "YPTS":
85 h = bs.ReadInt16();
86 bs.ReadInt16();
87 break;
88 case "ALTW":
89 eof = true;
90 Int16 heightScale = bs.ReadInt16();
91 Int16 baseHeight = bs.ReadInt16();
92 retval = new TerrainChannel(w, h);
93 int x;
94 for (x = 0; x < w; x++)
95 {
96 int y;
97 for (y = 0; y < h; y++)
98 {
99 retval[x, y] = baseHeight + bs.ReadInt16() * (double) heightScale / 65536.0;
100 }
101 }
102 break;
103 default:
104 bs.ReadInt32();
105 break;
106 }
107 }
108 }
109
110 bs.Close();
111
112 return retval;
113 }
114
115 public void SaveFile(string filename, ITerrainChannel map)
116 {
117 throw new NotImplementedException();
118 }
119
120 public void SaveStream(Stream stream, ITerrainChannel map)
121 {
122 throw new NotImplementedException();
123 }
124
125 public string FileExtension
126 {
127 get { return ".ter"; }
128 }
129
130 public ITerrainChannel LoadFile(string filename, int x, int y, int fileWidth, int fileHeight, int w, int h)
131 {
132 throw new NotImplementedException();
133 }
134
135 #endregion
136
137 public override string ToString()
138 {
139 return "Terragen";
140 }
141 }
142}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs
new file mode 100644
index 0000000..fe79c0b
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs
@@ -0,0 +1,70 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29
30namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
31{
32 public class FlattenArea : ITerrainFloodEffect
33 {
34 #region ITerrainFloodEffect Members
35
36 public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength)
37 {
38 double sum = 0.0;
39 double steps = 0.0;
40
41 int x, y;
42 for (x = 0; x < map.Width; x++)
43 {
44 for (y = 0; y < map.Height; y++)
45 {
46 if (fillArea[x, y])
47 {
48 sum += map[x, y];
49 steps += 1.0;
50 }
51 }
52 }
53
54 double avg = sum / steps;
55
56 double str = 0.1 * strength; // == 0.2 in the default client
57
58 for (x = 0; x < map.Width; x++)
59 {
60 for (y = 0; y < map.Height; y++)
61 {
62 if (fillArea[x, y])
63 map[x, y] = (map[x, y] * (1.0 - str)) + (avg * str);
64 }
65 }
66 }
67
68 #endregion
69 }
70} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs
new file mode 100644
index 0000000..5c0aace
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs
@@ -0,0 +1,54 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29
30namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
31{
32 public class LowerArea : ITerrainFloodEffect
33 {
34 #region ITerrainFloodEffect Members
35
36 public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength)
37 {
38 int x;
39 for (x = 0; x < map.Width; x++)
40 {
41 int y;
42 for (y = 0; y < map.Height; y++)
43 {
44 if (fillArea[x, y])
45 {
46 map[x, y] -= strength;
47 }
48 }
49 }
50 }
51
52 #endregion
53 }
54} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
new file mode 100644
index 0000000..02f2b53
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
@@ -0,0 +1,58 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
33{
34 public class NoiseArea : ITerrainFloodEffect
35 {
36 #region ITerrainFloodEffect Members
37
38 public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength)
39 {
40 int x;
41 for (x = 0; x < map.Width; x++)
42 {
43 int y;
44 for (y = 0; y < map.Height; y++)
45 {
46 if (fillArea[x, y])
47 {
48 double noise = TerrainUtil.PerlinNoise2D((double) x / Constants.RegionSize, (double) y / Constants.RegionSize, 8, 1.0);
49
50 map[x, y] += noise * strength;
51 }
52 }
53 }
54 }
55
56 #endregion
57 }
58} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs
new file mode 100644
index 0000000..768b31f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs
@@ -0,0 +1,54 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29
30namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
31{
32 public class RaiseArea : ITerrainFloodEffect
33 {
34 #region ITerrainFloodEffect Members
35
36 public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength)
37 {
38 int x;
39 for (x = 0; x < map.Width; x++)
40 {
41 int y;
42 for (y = 0; y < map.Height; y++)
43 {
44 if (fillArea[x, y])
45 {
46 map[x, y] += strength;
47 }
48 }
49 }
50 }
51
52 #endregion
53 }
54} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs
new file mode 100644
index 0000000..66b9055
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs
@@ -0,0 +1,67 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29
30namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
31{
32 public class RevertArea : ITerrainFloodEffect
33 {
34 private readonly ITerrainChannel m_revertmap;
35
36 public RevertArea(ITerrainChannel revertmap)
37 {
38 m_revertmap = revertmap;
39 }
40
41 #region ITerrainFloodEffect Members
42
43 /// <summary>
44 /// reverts an area of the map to the heightfield stored in the revertmap
45 /// </summary>
46 /// <param name="map">the current heightmap</param>
47 /// <param name="fillArea">array indicating which sections of the map are to be reverted</param>
48 /// <param name="strength">unused</param>
49 public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength)
50 {
51 int x;
52 for (x = 0; x < map.Width; x++)
53 {
54 int y;
55 for (y = 0; y < map.Height; y++)
56 {
57 if (fillArea[x, y])
58 {
59 map[x, y] = m_revertmap[x, y];
60 }
61 }
62 }
63 }
64
65 #endregion
66 }
67}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs
new file mode 100644
index 0000000..a75dde1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs
@@ -0,0 +1,114 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29
30namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
31{
32 public class SmoothArea : ITerrainFloodEffect
33 {
34 #region ITerrainFloodEffect Members
35
36 public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength)
37 {
38 double area = strength;
39 double step = strength / 4.0;
40
41 double[,] manipulate = new double[map.Width,map.Height];
42 int x, y;
43 for (x = 0; x < map.Width; x++)
44 {
45 for (y = 0; y < map.Height; y++)
46 {
47 if (!fillArea[x, y])
48 continue;
49
50 double average = 0.0;
51 int avgsteps = 0;
52
53 double n;
54 for (n = 0.0 - area; n < area; n += step)
55 {
56 double l;
57 for (l = 0.0 - area; l < area; l += step)
58 {
59 avgsteps++;
60 average += GetBilinearInterpolate(x + n, y + l, map);
61 }
62 }
63
64 manipulate[x, y] = average / avgsteps;
65 }
66 }
67 for (x = 0; x < map.Width; x++)
68 {
69 for (y = 0; y < map.Height; y++)
70 {
71 if (!fillArea[x, y])
72 continue;
73
74 map[x, y] = manipulate[x, y];
75 }
76 }
77 }
78
79 #endregion
80
81 private static double GetBilinearInterpolate(double x, double y, ITerrainChannel map)
82 {
83 int w = map.Width;
84 int h = map.Height;
85
86 if (x > w - 2.0)
87 x = w - 2.0;
88 if (y > h - 2.0)
89 y = h - 2.0;
90 if (x < 0.0)
91 x = 0.0;
92 if (y < 0.0)
93 y = 0.0;
94
95 const int stepSize = 1;
96 double h00 = map[(int) x, (int) y];
97 double h10 = map[(int) x + stepSize, (int) y];
98 double h01 = map[(int) x, (int) y + stepSize];
99 double h11 = map[(int) x + stepSize, (int) y + stepSize];
100 double h1 = h00;
101 double h2 = h10;
102 double h3 = h01;
103 double h4 = h11;
104 double a00 = h1;
105 double a10 = h2 - h1;
106 double a01 = h3 - h1;
107 double a11 = h1 - h2 - h3 + h4;
108 double partialx = x - (int) x;
109 double partialz = y - (int) y;
110 double hi = a00 + (a10 * partialx) + (a01 * partialz) + (a11 * partialx * partialz);
111 return hi;
112 }
113 }
114} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainEffect.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainEffect.cs
new file mode 100644
index 0000000..40b9f5a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainEffect.cs
@@ -0,0 +1,36 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29
30namespace OpenSim.Region.CoreModules.World.Terrain
31{
32 public interface ITerrainEffect
33 {
34 void RunEffect(ITerrainChannel map);
35 }
36} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs
new file mode 100644
index 0000000..eee7a83
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs
@@ -0,0 +1,37 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain
32{
33 public interface ITerrainFloodEffect
34 {
35 void FloodEffect(ITerrainChannel map, Boolean[,] fillArea, double strength);
36 }
37} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs
new file mode 100644
index 0000000..c62b897
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs
@@ -0,0 +1,42 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.IO;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain
32{
33 public interface ITerrainLoader
34 {
35 string FileExtension { get; }
36 ITerrainChannel LoadFile(string filename);
37 ITerrainChannel LoadFile(string filename, int fileStartX, int fileStartY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight);
38 ITerrainChannel LoadStream(Stream stream);
39 void SaveFile(string filename, ITerrainChannel map);
40 void SaveStream(Stream stream, ITerrainChannel map);
41 }
42} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModule.cs
new file mode 100644
index 0000000..8c5d1d9
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModule.cs
@@ -0,0 +1,61 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29using System.IO;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Region.CoreModules.World.Terrain
34{
35 public interface ITerrainModule
36 {
37 void LoadFromFile(string filename);
38 void SaveToFile(string filename);
39 void ModifyTerrain(UUID user, Vector3 pos, byte size, byte action, UUID agentId);
40
41 /// <summary>
42 /// Load a terrain from a stream.
43 /// </summary>
44 /// <param name="filename">
45 /// Only required here to identify the image type. Not otherwise used in the loading itself.
46 /// </param>
47 /// <param name="stream"></param>
48 void LoadFromStream(string filename, Stream stream);
49
50 /// <summary>
51 /// Save a terrain to a stream.
52 /// </summary>
53 /// <param name="filename">
54 /// Only required here to identify the image type. Not otherwise used in the saving itself.
55 /// </param>
56 /// <param name="stream"></param>
57 void SaveToStream(string filename, Stream stream);
58
59 void InstallPlugin(string name, ITerrainEffect plug);
60 }
61}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs
new file mode 100644
index 0000000..15d9f6e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs
@@ -0,0 +1,36 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29
30namespace OpenSim.Region.CoreModules.World.Terrain
31{
32 public interface ITerrainPaintableEffect
33 {
34 void PaintEffect(ITerrainChannel map, bool[,] allowMask, double x, double y, double z, double strength, double duration);
35 }
36}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs
new file mode 100644
index 0000000..6ce6994
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs
@@ -0,0 +1,318 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
33{
34 /// <summary>
35 /// Hydraulic Erosion Brush
36 /// </summary>
37 public class ErodeSphere : ITerrainPaintableEffect
38 {
39 private const double rainHeight = 0.2;
40 private const int rounds = 10;
41 private const NeighbourSystem type = NeighbourSystem.Moore;
42 private const double waterSaturation = 0.30;
43
44 #region Supporting Functions
45
46 private static int[] Neighbours(NeighbourSystem neighbourType, int index)
47 {
48 int[] coord = new int[2];
49
50 index++;
51
52 switch (neighbourType)
53 {
54 case NeighbourSystem.Moore:
55 switch (index)
56 {
57 case 1:
58 coord[0] = -1;
59 coord[1] = -1;
60 break;
61
62 case 2:
63 coord[0] = -0;
64 coord[1] = -1;
65 break;
66
67 case 3:
68 coord[0] = +1;
69 coord[1] = -1;
70 break;
71
72 case 4:
73 coord[0] = -1;
74 coord[1] = -0;
75 break;
76
77 case 5:
78 coord[0] = -0;
79 coord[1] = -0;
80 break;
81
82 case 6:
83 coord[0] = +1;
84 coord[1] = -0;
85 break;
86
87 case 7:
88 coord[0] = -1;
89 coord[1] = +1;
90 break;
91
92 case 8:
93 coord[0] = -0;
94 coord[1] = +1;
95 break;
96
97 case 9:
98 coord[0] = +1;
99 coord[1] = +1;
100 break;
101
102 default:
103 break;
104 }
105 break;
106
107 case NeighbourSystem.VonNeumann:
108 switch (index)
109 {
110 case 1:
111 coord[0] = 0;
112 coord[1] = -1;
113 break;
114
115 case 2:
116 coord[0] = -1;
117 coord[1] = 0;
118 break;
119
120 case 3:
121 coord[0] = +1;
122 coord[1] = 0;
123 break;
124
125 case 4:
126 coord[0] = 0;
127 coord[1] = +1;
128 break;
129
130 case 5:
131 coord[0] = -0;
132 coord[1] = -0;
133 break;
134
135 default:
136 break;
137 }
138 break;
139 }
140
141 return coord;
142 }
143
144 private enum NeighbourSystem
145 {
146 Moore,
147 VonNeumann
148 } ;
149
150 #endregion
151
152 #region ITerrainPaintableEffect Members
153
154 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
155 {
156 strength = TerrainUtil.MetersToSphericalStrength(strength);
157
158 int x, y;
159 // Using one 'rain' round for this, so skipping a useless loop
160 // Will need to adapt back in for the Flood brush
161
162 ITerrainChannel water = new TerrainChannel(map.Width, map.Height);
163 ITerrainChannel sediment = new TerrainChannel(map.Width, map.Height);
164
165 // Fill with rain
166 for (x = 0; x < water.Width; x++)
167 for (y = 0; y < water.Height; y++)
168 water[x, y] = Math.Max(0.0, TerrainUtil.SphericalFactor(x, y, rx, ry, strength) * rainHeight * duration);
169
170 for (int i = 0; i < rounds; i++)
171 {
172 // Erode underlying terrain
173 for (x = 0; x < water.Width; x++)
174 {
175 for (y = 0; y < water.Height; y++)
176 {
177 if (mask[x,y])
178 {
179 const double solConst = (1.0 / rounds);
180 double sedDelta = water[x, y] * solConst;
181 map[x, y] -= sedDelta;
182 sediment[x, y] += sedDelta;
183 }
184 }
185 }
186
187 // Move water
188 for (x = 0; x < water.Width; x++)
189 {
190 for (y = 0; y < water.Height; y++)
191 {
192 if (water[x, y] <= 0)
193 continue;
194
195 // Step 1. Calculate average of neighbours
196
197 int neighbours = 0;
198 double altitudeTotal = 0.0;
199 double altitudeMe = map[x, y] + water[x, y];
200
201 const int NEIGHBOUR_ME = 4;
202 const int NEIGHBOUR_MAX = 9;
203
204 for (int j = 0; j < NEIGHBOUR_MAX; j++)
205 {
206 if (j != NEIGHBOUR_ME)
207 {
208 int[] coords = Neighbours(type, j);
209
210 coords[0] += x;
211 coords[1] += y;
212
213 if (coords[0] > map.Width - 1)
214 continue;
215 if (coords[1] > map.Height - 1)
216 continue;
217 if (coords[0] < 0)
218 continue;
219 if (coords[1] < 0)
220 continue;
221
222 // Calculate total height of this neighbour
223 double altitudeNeighbour = water[coords[0], coords[1]] + map[coords[0], coords[1]];
224
225 // If it's greater than me...
226 if (altitudeNeighbour - altitudeMe < 0)
227 {
228 // Add it to our calculations
229 neighbours++;
230 altitudeTotal += altitudeNeighbour;
231 }
232 }
233 }
234
235 if (neighbours == 0)
236 continue;
237
238 double altitudeAvg = altitudeTotal / neighbours;
239
240 // Step 2. Allocate water to neighbours.
241 for (int j = 0; j < NEIGHBOUR_MAX; j++)
242 {
243 if (j != NEIGHBOUR_ME)
244 {
245 int[] coords = Neighbours(type, j);
246
247 coords[0] += x;
248 coords[1] += y;
249
250 if (coords[0] > map.Width - 1)
251 continue;
252 if (coords[1] > map.Height - 1)
253 continue;
254 if (coords[0] < 0)
255 continue;
256 if (coords[1] < 0)
257 continue;
258
259 // Skip if we dont have water to begin with.
260 if (water[x, y] < 0)
261 continue;
262
263 // Calculate our delta average
264 double altitudeDelta = altitudeMe - altitudeAvg;
265
266 if (altitudeDelta < 0)
267 continue;
268
269 // Calculate how much water we can move
270 double waterMin = Math.Min(water[x, y], altitudeDelta);
271 double waterDelta = waterMin * ((water[coords[0], coords[1]] + map[coords[0], coords[1]])
272 / altitudeTotal);
273
274 double sedimentDelta = sediment[x, y] * (waterDelta / water[x, y]);
275
276 if (sedimentDelta > 0)
277 {
278 sediment[x, y] -= sedimentDelta;
279 sediment[coords[0], coords[1]] += sedimentDelta;
280 }
281 }
282 }
283 }
284 }
285
286 // Evaporate
287
288 for (x = 0; x < water.Width; x++)
289 {
290 for (y = 0; y < water.Height; y++)
291 {
292 water[x, y] *= 1.0 - (rainHeight / rounds);
293
294 double waterCapacity = waterSaturation * water[x, y];
295
296 double sedimentDeposit = sediment[x, y] - waterCapacity;
297 if (sedimentDeposit > 0)
298 {
299 if (mask[x,y])
300 {
301 sediment[x, y] -= sedimentDeposit;
302 map[x, y] += sedimentDeposit;
303 }
304 }
305 }
306 }
307 }
308
309 // Deposit any remainder (should be minimal)
310 for (x = 0; x < water.Width; x++)
311 for (y = 0; y < water.Height; y++)
312 if (mask[x,y] && sediment[x, y] > 0)
313 map[x, y] += sediment[x, y];
314 }
315
316 #endregion
317 }
318}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs
new file mode 100644
index 0000000..928a595
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs
@@ -0,0 +1,101 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
33{
34 public class FlattenSphere : ITerrainPaintableEffect
35 {
36 #region ITerrainPaintableEffect Members
37
38 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
39 {
40 strength = TerrainUtil.MetersToSphericalStrength(strength);
41
42 int x, y;
43
44 if (rz < 0) {
45 double sum = 0.0;
46 double step2 = 0.0;
47 duration = 0.009; //MCP Should be read from ini file
48
49
50 // compute delta map
51 for (x = 0; x < map.Width; x++)
52 {
53 for (y = 0; y < map.Height; y++)
54 {
55 double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength);
56
57 if (z > 0) // add in non-zero amount
58 {
59 sum += map[x, y] * z;
60 step2 += z;
61 }
62 }
63 }
64 rz = sum / step2;
65 }
66
67
68 // blend in map
69 for (x = 0; x < map.Width; x++)
70 {
71 for (y = 0; y < map.Height; y++)
72 {
73 if (!mask[x,y])
74 continue;
75
76 double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength) * duration;
77
78 if (z > 0) // add in non-zero amount
79 {
80 if (z > 1.0)
81 z = 1.0;
82
83 map[x, y] = (map[x, y] * (1.0 - z)) + (rz * z);
84 }
85
86 double delta = rz - map[x, y];
87 if (Math.Abs(delta) > 0.1)
88 delta *= 0.25;
89
90 if (delta != 0) // add in non-zero amount
91 {
92 map[x, y] += delta;
93 }
94
95 }
96 }
97 }
98
99 #endregion
100 }
101}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs
new file mode 100644
index 0000000..8c40088
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs
@@ -0,0 +1,84 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
32{
33 public class LowerSphere : ITerrainPaintableEffect
34 {
35 #region ITerrainPaintableEffect Members
36
37 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
38 {
39 int s = (int) (Math.Pow(2, strength) + 0.5);
40
41 int x;
42 int xFrom = (int)(rx-s+0.5);
43 int xTo = (int)(rx+s+0.5) + 1;
44 int yFrom = (int)(ry-s+0.5);
45 int yTo = (int)(ry+s+0.5) + 1;
46
47 if (xFrom < 0)
48 xFrom = 0;
49
50 if (yFrom < 0)
51 yFrom = 0;
52
53 if (xTo > map.Width)
54 xTo = map.Width;
55
56 if (yTo > map.Width)
57 yTo = map.Width;
58
59 for (x = xFrom; x < xTo; x++)
60 {
61 int y;
62 for (y = yFrom; y < yTo; y++)
63 {
64 if (!mask[x,y])
65 continue;
66
67 // Calculate a cos-sphere and add it to the heighmap
68 double r = Math.Sqrt((x-rx) * (x-rx) + ((y-ry) * (y-ry)));
69 double z = Math.Cos(r * Math.PI / (s * 2));
70 if (z > 0.0)
71 {
72 double newz = map[x, y] - z * duration;
73 if (newz < 0.0)
74 map[x, y] = 0.0;
75 else
76 map[x, y] = newz;
77 }
78 }
79 }
80
81 }
82 #endregion
83 }
84}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
new file mode 100644
index 0000000..95a8c33
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
@@ -0,0 +1,67 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using OpenSim.Region.Framework.Interfaces;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
34{
35 public class NoiseSphere : ITerrainPaintableEffect
36 {
37 #region ITerrainPaintableEffect Members
38
39 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
40 {
41 strength = TerrainUtil.MetersToSphericalStrength(strength);
42
43 int x;
44 for (x = 0; x < map.Width; x++)
45 {
46 int y;
47 for (y = 0; y < map.Height; y++)
48 {
49 if (!mask[x,y])
50 continue;
51
52 // Calculate a sphere and add it to the heighmap
53 double z = strength;
54 z *= z;
55 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry));
56
57 double noise = TerrainUtil.PerlinNoise2D(x / (double) Constants.RegionSize, y / (double) Constants.RegionSize, 8, 1.0);
58
59 if (z > 0.0)
60 map[x, y] += noise * z * duration;
61 }
62 }
63 }
64
65 #endregion
66 }
67}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs
new file mode 100644
index 0000000..1a2528a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs
@@ -0,0 +1,223 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
33{
34 /// <summary>
35 /// Speed-Optimised Hybrid Erosion Brush
36 ///
37 /// As per Jacob Olsen's Paper
38 /// http://www.oddlabs.com/download/terrain_generation.pdf
39 /// </summary>
40 public class OlsenSphere : ITerrainPaintableEffect
41 {
42 private const double nConst = 1024.0;
43 private const NeighbourSystem type = NeighbourSystem.Moore;
44
45 #region Supporting Functions
46
47 private static int[] Neighbours(NeighbourSystem neighbourType, int index)
48 {
49 int[] coord = new int[2];
50
51 index++;
52
53 switch (neighbourType)
54 {
55 case NeighbourSystem.Moore:
56 switch (index)
57 {
58 case 1:
59 coord[0] = -1;
60 coord[1] = -1;
61 break;
62
63 case 2:
64 coord[0] = -0;
65 coord[1] = -1;
66 break;
67
68 case 3:
69 coord[0] = +1;
70 coord[1] = -1;
71 break;
72
73 case 4:
74 coord[0] = -1;
75 coord[1] = -0;
76 break;
77
78 case 5:
79 coord[0] = -0;
80 coord[1] = -0;
81 break;
82
83 case 6:
84 coord[0] = +1;
85 coord[1] = -0;
86 break;
87
88 case 7:
89 coord[0] = -1;
90 coord[1] = +1;
91 break;
92
93 case 8:
94 coord[0] = -0;
95 coord[1] = +1;
96 break;
97
98 case 9:
99 coord[0] = +1;
100 coord[1] = +1;
101 break;
102
103 default:
104 break;
105 }
106 break;
107
108 case NeighbourSystem.VonNeumann:
109 switch (index)
110 {
111 case 1:
112 coord[0] = 0;
113 coord[1] = -1;
114 break;
115
116 case 2:
117 coord[0] = -1;
118 coord[1] = 0;
119 break;
120
121 case 3:
122 coord[0] = +1;
123 coord[1] = 0;
124 break;
125
126 case 4:
127 coord[0] = 0;
128 coord[1] = +1;
129 break;
130
131 case 5:
132 coord[0] = -0;
133 coord[1] = -0;
134 break;
135
136 default:
137 break;
138 }
139 break;
140 }
141
142 return coord;
143 }
144
145 private enum NeighbourSystem
146 {
147 Moore,
148 VonNeumann
149 } ;
150
151 #endregion
152
153 #region ITerrainPaintableEffect Members
154
155 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
156 {
157 strength = TerrainUtil.MetersToSphericalStrength(strength);
158
159 int x;
160
161 for (x = 0; x < map.Width; x++)
162 {
163 int y;
164 for (y = 0; y < map.Height; y++)
165 {
166 if (!mask[x,y])
167 continue;
168
169 double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength);
170
171 if (z > 0) // add in non-zero amount
172 {
173 const int NEIGHBOUR_ME = 4;
174 const int NEIGHBOUR_MAX = 9;
175
176 double max = Double.MinValue;
177 int loc = 0;
178
179
180 for (int j = 0; j < NEIGHBOUR_MAX; j++)
181 {
182 if (j != NEIGHBOUR_ME)
183 {
184 int[] coords = Neighbours(type, j);
185
186 coords[0] += x;
187 coords[1] += y;
188
189 if (coords[0] > map.Width - 1)
190 continue;
191 if (coords[1] > map.Height - 1)
192 continue;
193 if (coords[0] < 0)
194 continue;
195 if (coords[1] < 0)
196 continue;
197
198 double cellmax = map[x, y] - map[coords[0], coords[1]];
199 if (cellmax > max)
200 {
201 max = cellmax;
202 loc = j;
203 }
204 }
205 }
206
207 double T = nConst / ((map.Width + map.Height) / 2.0);
208 // Apply results
209 if (0 < max && max <= T)
210 {
211 int[] maxCoords = Neighbours(type, loc);
212 double heightDelta = 0.5 * max * z * duration;
213 map[x, y] -= heightDelta;
214 map[x + maxCoords[0], y + maxCoords[1]] += heightDelta;
215 }
216 }
217 }
218 }
219 }
220
221 #endregion
222 }
223}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs
new file mode 100644
index 0000000..c53bb7d
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs
@@ -0,0 +1,80 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
33{
34 public class RaiseSphere : ITerrainPaintableEffect
35 {
36 #region ITerrainPaintableEffect Members
37
38
39 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
40 {
41 int s = (int) (Math.Pow(2, strength) + 0.5);
42
43 int x;
44 int xFrom = (int)(rx-s+0.5);
45 int xTo = (int)(rx+s+0.5) + 1;
46 int yFrom = (int)(ry-s+0.5);
47 int yTo = (int)(ry+s+0.5) + 1;
48
49 if (xFrom < 0)
50 xFrom = 0;
51
52 if (yFrom < 0)
53 yFrom = 0;
54
55 if (xTo > map.Width)
56 xTo = map.Width;
57
58 if (yTo > map.Width)
59 yTo = map.Width;
60
61 for (x = xFrom; x < xTo; x++)
62 {
63 int y;
64 for (y = yFrom; y < yTo; y++)
65 {
66 if (!mask[x,y])
67 continue;
68
69 // Calculate a cos-sphere and add it to the heighmap
70 double r = Math.Sqrt((x-rx) * (x-rx) + ((y-ry) * (y-ry)));
71 double z = Math.Cos(r * Math.PI / (s * 2));
72 if (z > 0.0)
73 map[x, y] += z * duration;
74 }
75 }
76 }
77
78 #endregion
79 }
80}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs
new file mode 100644
index 0000000..4ed8a13
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs
@@ -0,0 +1,80 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
33{
34 public class RevertSphere : ITerrainPaintableEffect
35 {
36 private readonly ITerrainChannel m_revertmap;
37
38 public RevertSphere(ITerrainChannel revertmap)
39 {
40 m_revertmap = revertmap;
41 }
42
43 #region ITerrainPaintableEffect Members
44
45 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
46 {
47 strength = TerrainUtil.MetersToSphericalStrength(strength);
48 duration = 0.03; //MCP Should be read from ini file
49
50 if (duration > 1.0)
51 duration = 1.0;
52 if (duration < 0)
53 return;
54
55 int x;
56 for (x = 0; x < map.Width; x++)
57 {
58 int y;
59 for (y = 0; y < map.Height; y++)
60 {
61 if (!mask[x,y])
62 continue;
63
64 // Calculate a sphere and add it to the heighmap
65 double z = strength;
66 z *= z;
67 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry));
68
69 if (z > 0.0)
70 {
71 z *= duration;
72 map[x, y] = (map[x, y] * (1.0 - z)) + (m_revertmap[x, y] * z);
73 }
74 }
75 }
76 }
77
78 #endregion
79 }
80}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs
new file mode 100644
index 0000000..6636d8f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs
@@ -0,0 +1,100 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29using OpenSim.Region.Framework.Scenes;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
32{
33 public class SmoothSphere : ITerrainPaintableEffect
34 {
35 #region ITerrainPaintableEffect Members
36
37 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
38 {
39 strength = TerrainUtil.MetersToSphericalStrength(strength);
40
41 int x, y;
42 double[,] tweak = new double[map.Width,map.Height];
43
44 double area = strength;
45 double step = strength / 4.0;
46 duration = 0.03; //MCP Should be read from ini file
47
48
49 // compute delta map
50 for (x = 0; x < map.Width; x++)
51 {
52 for (y = 0; y < map.Height; y++)
53 {
54 double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength);
55
56 if (z > 0) // add in non-zero amount
57 {
58 double average = 0.0;
59 int avgsteps = 0;
60
61 double n;
62 for (n = 0.0 - area; n < area; n += step)
63 {
64 double l;
65 for (l = 0.0 - area; l < area; l += step)
66 {
67 avgsteps++;
68 average += TerrainUtil.GetBilinearInterpolate(x + n, y + l, map);
69 }
70 }
71 tweak[x, y] = average / avgsteps;
72 }
73 }
74 }
75 // blend in map
76 for (x = 0; x < map.Width; x++)
77 {
78 for (y = 0; y < map.Height; y++)
79 {
80 if (!mask[x,y])
81 continue;
82
83 double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength);
84
85 if (z > 0) // add in non-zero amount
86 {
87 double da = z;
88 double a = (map[x, y] - tweak[x, y]) * da;
89 double newz = map[x, y] - (a * duration);
90
91 if (newz > 0.0)
92 map[x, y] = newz;
93 }
94 }
95 }
96 }
97
98 #endregion
99 }
100}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs
new file mode 100644
index 0000000..6b00cc8
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs
@@ -0,0 +1,211 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.Framework.Interfaces;
29using OpenSim.Region.Framework.Scenes;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
32{
33 /// <summary>
34 /// Thermal Weathering Paint Brush
35 /// </summary>
36 public class WeatherSphere : ITerrainPaintableEffect
37 {
38 private const double talus = 0.2;
39 private const NeighbourSystem type = NeighbourSystem.Moore;
40
41 #region Supporting Functions
42
43 private static int[] Neighbours(NeighbourSystem neighbourType, int index)
44 {
45 int[] coord = new int[2];
46
47 index++;
48
49 switch (neighbourType)
50 {
51 case NeighbourSystem.Moore:
52 switch (index)
53 {
54 case 1:
55 coord[0] = -1;
56 coord[1] = -1;
57 break;
58
59 case 2:
60 coord[0] = -0;
61 coord[1] = -1;
62 break;
63
64 case 3:
65 coord[0] = +1;
66 coord[1] = -1;
67 break;
68
69 case 4:
70 coord[0] = -1;
71 coord[1] = -0;
72 break;
73
74 case 5:
75 coord[0] = -0;
76 coord[1] = -0;
77 break;
78
79 case 6:
80 coord[0] = +1;
81 coord[1] = -0;
82 break;
83
84 case 7:
85 coord[0] = -1;
86 coord[1] = +1;
87 break;
88
89 case 8:
90 coord[0] = -0;
91 coord[1] = +1;
92 break;
93
94 case 9:
95 coord[0] = +1;
96 coord[1] = +1;
97 break;
98
99 default:
100 break;
101 }
102 break;
103
104 case NeighbourSystem.VonNeumann:
105 switch (index)
106 {
107 case 1:
108 coord[0] = 0;
109 coord[1] = -1;
110 break;
111
112 case 2:
113 coord[0] = -1;
114 coord[1] = 0;
115 break;
116
117 case 3:
118 coord[0] = +1;
119 coord[1] = 0;
120 break;
121
122 case 4:
123 coord[0] = 0;
124 coord[1] = +1;
125 break;
126
127 case 5:
128 coord[0] = -0;
129 coord[1] = -0;
130 break;
131
132 default:
133 break;
134 }
135 break;
136 }
137
138 return coord;
139 }
140
141 private enum NeighbourSystem
142 {
143 Moore,
144 VonNeumann
145 } ;
146
147 #endregion
148
149 #region ITerrainPaintableEffect Members
150
151 public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration)
152 {
153 strength = TerrainUtil.MetersToSphericalStrength(strength);
154
155 int x;
156
157 for (x = 0; x < map.Width; x++)
158 {
159 int y;
160 for (y = 0; y < map.Height; y++)
161 {
162 if (!mask[x,y])
163 continue;
164
165 double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength);
166
167 if (z > 0) // add in non-zero amount
168 {
169 const int NEIGHBOUR_ME = 4;
170 const int NEIGHBOUR_MAX = 9;
171
172 for (int j = 0; j < NEIGHBOUR_MAX; j++)
173 {
174 if (j != NEIGHBOUR_ME)
175 {
176 int[] coords = Neighbours(type, j);
177
178 coords[0] += x;
179 coords[1] += y;
180
181 if (coords[0] > map.Width - 1)
182 continue;
183 if (coords[1] > map.Height - 1)
184 continue;
185 if (coords[0] < 0)
186 continue;
187 if (coords[1] < 0)
188 continue;
189
190 double heightF = map[x, y];
191 double target = map[coords[0], coords[1]];
192
193 if (target > heightF + talus)
194 {
195 double calc = duration * ((target - heightF) - talus) * z;
196 heightF += calc;
197 target -= calc;
198 }
199
200 map[x, y] = heightF;
201 map[coords[0], coords[1]] = target;
202 }
203 }
204 }
205 }
206 }
207 }
208
209 #endregion
210 }
211}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainException.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainException.cs
new file mode 100644
index 0000000..ff9b8ec
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainException.cs
@@ -0,0 +1,46 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29
30namespace OpenSim.Region.CoreModules.World.Terrain
31{
32 public class TerrainException : Exception
33 {
34 public TerrainException()
35 {
36 }
37
38 public TerrainException(string msg) : base(msg)
39 {
40 }
41
42 public TerrainException(string msg, Exception e) : base(msg, e)
43 {
44 }
45 }
46} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
new file mode 100644
index 0000000..9de7338
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -0,0 +1,1001 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using OpenMetaverse;
33using log4net;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
39using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
40using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes;
41using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
42
43namespace OpenSim.Region.CoreModules.World.Terrain
44{
45 public class TerrainModule : IRegionModule, ICommandableModule, ITerrainModule
46 {
47 #region StandardTerrainEffects enum
48
49 /// <summary>
50 /// A standard set of terrain brushes and effects recognised by viewers
51 /// </summary>
52 public enum StandardTerrainEffects : byte
53 {
54 Flatten = 0,
55 Raise = 1,
56 Lower = 2,
57 Smooth = 3,
58 Noise = 4,
59 Revert = 5,
60
61 // Extended brushes
62 Erode = 255,
63 Weather = 254,
64 Olsen = 253
65 }
66
67 #endregion
68
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
71 private readonly Commander m_commander = new Commander("terrain");
72
73 private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects =
74 new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>();
75
76 private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>();
77
78 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
79 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
80
81 private ITerrainChannel m_channel;
82 private Dictionary<string, ITerrainEffect> m_plugineffects;
83 private ITerrainChannel m_revert;
84 private Scene m_scene;
85 private bool m_tainted;
86
87 #region ICommandableModule Members
88
89 public ICommander CommandInterface
90 {
91 get { return m_commander; }
92 }
93
94 #endregion
95
96 #region IRegionModule Members
97
98 /// <summary>
99 /// Creates and initialises a terrain module for a region
100 /// </summary>
101 /// <param name="scene">Region initialising</param>
102 /// <param name="config">Config for the region</param>
103 public void Initialise(Scene scene, IConfigSource config)
104 {
105 m_scene = scene;
106
107 // Install terrain module in the simulator
108 if (m_scene.Heightmap == null)
109 {
110 lock (m_scene)
111 {
112 m_channel = new TerrainChannel();
113 m_scene.Heightmap = m_channel;
114 m_revert = new TerrainChannel();
115 UpdateRevertMap();
116 }
117 }
118 else
119 {
120 m_channel = m_scene.Heightmap;
121 m_revert = new TerrainChannel();
122 UpdateRevertMap();
123 }
124
125 m_scene.RegisterModuleInterface<ITerrainModule>(this);
126 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
127 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
128 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick;
129 }
130
131 /// <summary>
132 /// Enables terrain module when called
133 /// </summary>
134 public void PostInitialise()
135 {
136 InstallDefaultEffects();
137 InstallInterfaces();
138 LoadPlugins();
139 }
140
141 public void Close()
142 {
143 }
144
145 public string Name
146 {
147 get { return "TerrainModule"; }
148 }
149
150 public bool IsSharedModule
151 {
152 get { return false; }
153 }
154
155 #endregion
156
157 #region ITerrainModule Members
158
159 /// <summary>
160 /// Loads a terrain file from disk and installs it in the scene.
161 /// </summary>
162 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
163 public void LoadFromFile(string filename)
164 {
165 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
166 {
167 if (filename.EndsWith(loader.Key))
168 {
169 lock (m_scene)
170 {
171 try
172 {
173 ITerrainChannel channel = loader.Value.LoadFile(filename);
174 if (channel.Width != Constants.RegionSize || channel.Height != Constants.RegionSize)
175 {
176 // TerrainChannel expects a RegionSize x RegionSize map, currently
177 throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}",
178 Constants.RegionSize, Constants.RegionSize));
179 }
180 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height);
181 m_scene.Heightmap = channel;
182 m_channel = channel;
183 UpdateRevertMap();
184 }
185 catch (NotImplementedException)
186 {
187 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
188 " parser does not support file loading. (May be save only)");
189 throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value));
190 }
191 catch (FileNotFoundException)
192 {
193 m_log.Error(
194 "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)");
195 throw new TerrainException(
196 String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename));
197 }
198 catch (ArgumentException e)
199 {
200 m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message);
201 throw new TerrainException(
202 String.Format("Unable to load heightmap: {0}", e.Message));
203 }
204 }
205 CheckForTerrainUpdates();
206 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
207 return;
208 }
209 }
210
211 m_log.Error("[TERRAIN]: Unable to load heightmap, no file loader available for that format.");
212 throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename));
213 }
214
215 /// <summary>
216 /// Saves the current heightmap to a specified file.
217 /// </summary>
218 /// <param name="filename">The destination filename</param>
219 public void SaveToFile(string filename)
220 {
221 try
222 {
223 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
224 {
225 if (filename.EndsWith(loader.Key))
226 {
227 loader.Value.SaveFile(filename, m_channel);
228 return;
229 }
230 }
231 }
232 catch (NotImplementedException)
233 {
234 m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented.");
235 throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented"));
236 }
237 }
238
239 /// <summary>
240 /// Loads a terrain file from a stream and installs it in the scene.
241 /// </summary>
242 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
243 /// <param name="stream"></param>
244 public void LoadFromStream(string filename, Stream stream)
245 {
246 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
247 {
248 if (@filename.EndsWith(loader.Key))
249 {
250 lock (m_scene)
251 {
252 try
253 {
254 ITerrainChannel channel = loader.Value.LoadStream(stream);
255 m_scene.Heightmap = channel;
256 m_channel = channel;
257 UpdateRevertMap();
258 }
259 catch (NotImplementedException)
260 {
261 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
262 " parser does not support file loading. (May be save only)");
263 throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value));
264 }
265 }
266
267 CheckForTerrainUpdates();
268 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
269 return;
270 }
271 }
272 m_log.Error("[TERRAIN]: Unable to load heightmap, no file loader available for that format.");
273 throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename));
274 }
275
276 /// <summary>
277 /// Modify Land
278 /// </summary>
279 /// <param name="pos">Land-position (X,Y,0)</param>
280 /// <param name="size">The size of the brush (0=small, 1=medium, 2=large)</param>
281 /// <param name="action">0=LAND_LEVEL, 1=LAND_RAISE, 2=LAND_LOWER, 3=LAND_SMOOTH, 4=LAND_NOISE, 5=LAND_REVERT</param>
282 /// <param name="agentId">UUID of script-owner</param>
283 public void ModifyTerrain(UUID user, Vector3 pos, byte size, byte action, UUID agentId)
284 {
285 client_OnModifyTerrain(user, (float)pos.Z, (float)0.25, size, action, pos.Y, pos.X, pos.Y, pos.X, agentId);
286 }
287
288 /// <summary>
289 /// Saves the current heightmap to a specified stream.
290 /// </summary>
291 /// <param name="filename">The destination filename. Used here only to identify the image type</param>
292 /// <param name="stream"></param>
293 public void SaveToStream(string filename, Stream stream)
294 {
295 try
296 {
297 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
298 {
299 if (filename.EndsWith(loader.Key))
300 {
301 loader.Value.SaveStream(stream, m_channel);
302 return;
303 }
304 }
305 }
306 catch (NotImplementedException)
307 {
308 m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented.");
309 throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented"));
310 }
311 }
312
313 #region Plugin Loading Methods
314
315 private void LoadPlugins()
316 {
317 m_plugineffects = new Dictionary<string, ITerrainEffect>();
318 // Load the files in the Terrain/ dir
319 string[] files = Directory.GetFiles("Terrain");
320 foreach (string file in files)
321 {
322 m_log.Info("Loading effects in " + file);
323 try
324 {
325 Assembly library = Assembly.LoadFrom(file);
326 foreach (Type pluginType in library.GetTypes())
327 {
328 try
329 {
330 if (pluginType.IsAbstract || pluginType.IsNotPublic)
331 continue;
332
333 string typeName = pluginType.Name;
334
335 if (pluginType.GetInterface("ITerrainEffect", false) != null)
336 {
337 ITerrainEffect terEffect = (ITerrainEffect) Activator.CreateInstance(library.GetType(pluginType.ToString()));
338
339 InstallPlugin(typeName, terEffect);
340 }
341 else if (pluginType.GetInterface("ITerrainLoader", false) != null)
342 {
343 ITerrainLoader terLoader = (ITerrainLoader) Activator.CreateInstance(library.GetType(pluginType.ToString()));
344 m_loaders[terLoader.FileExtension] = terLoader;
345 m_log.Info("L ... " + typeName);
346 }
347 }
348 catch (AmbiguousMatchException)
349 {
350 }
351 }
352 }
353 catch (BadImageFormatException)
354 {
355 }
356 }
357 }
358
359 public void InstallPlugin(string pluginName, ITerrainEffect effect)
360 {
361 lock (m_plugineffects)
362 {
363 if (!m_plugineffects.ContainsKey(pluginName))
364 {
365 m_plugineffects.Add(pluginName, effect);
366 m_log.Info("E ... " + pluginName);
367 }
368 else
369 {
370 m_plugineffects[pluginName] = effect;
371 m_log.Warn("E ... " + pluginName + " (Replaced)");
372 }
373 }
374 }
375
376 #endregion
377
378 #endregion
379
380 /// <summary>
381 /// Installs into terrain module the standard suite of brushes
382 /// </summary>
383 private void InstallDefaultEffects()
384 {
385 // Draggable Paint Brush Effects
386 m_painteffects[StandardTerrainEffects.Raise] = new RaiseSphere();
387 m_painteffects[StandardTerrainEffects.Lower] = new LowerSphere();
388 m_painteffects[StandardTerrainEffects.Smooth] = new SmoothSphere();
389 m_painteffects[StandardTerrainEffects.Noise] = new NoiseSphere();
390 m_painteffects[StandardTerrainEffects.Flatten] = new FlattenSphere();
391 m_painteffects[StandardTerrainEffects.Revert] = new RevertSphere(m_revert);
392 m_painteffects[StandardTerrainEffects.Erode] = new ErodeSphere();
393 m_painteffects[StandardTerrainEffects.Weather] = new WeatherSphere();
394 m_painteffects[StandardTerrainEffects.Olsen] = new OlsenSphere();
395
396 // Area of effect selection effects
397 m_floodeffects[StandardTerrainEffects.Raise] = new RaiseArea();
398 m_floodeffects[StandardTerrainEffects.Lower] = new LowerArea();
399 m_floodeffects[StandardTerrainEffects.Smooth] = new SmoothArea();
400 m_floodeffects[StandardTerrainEffects.Noise] = new NoiseArea();
401 m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea();
402 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert);
403
404 // Filesystem load/save loaders
405 m_loaders[".r32"] = new RAW32();
406 m_loaders[".f32"] = m_loaders[".r32"];
407 m_loaders[".ter"] = new Terragen();
408 m_loaders[".raw"] = new LLRAW();
409 m_loaders[".jpg"] = new JPEG();
410 m_loaders[".jpeg"] = m_loaders[".jpg"];
411 m_loaders[".bmp"] = new BMP();
412 m_loaders[".png"] = new PNG();
413 m_loaders[".gif"] = new GIF();
414 m_loaders[".tif"] = new TIFF();
415 m_loaders[".tiff"] = m_loaders[".tif"];
416 }
417
418 /// <summary>
419 /// Saves the current state of the region into the revert map buffer.
420 /// </summary>
421 public void UpdateRevertMap()
422 {
423 int x;
424 for (x = 0; x < m_channel.Width; x++)
425 {
426 int y;
427 for (y = 0; y < m_channel.Height; y++)
428 {
429 m_revert[x, y] = m_channel[x, y];
430 }
431 }
432 }
433
434 /// <summary>
435 /// Loads a tile from a larger terrain file and installs it into the region.
436 /// </summary>
437 /// <param name="filename">The terrain file to load</param>
438 /// <param name="fileWidth">The width of the file in units</param>
439 /// <param name="fileHeight">The height of the file in units</param>
440 /// <param name="fileStartX">Where to begin our slice</param>
441 /// <param name="fileStartY">Where to begin our slice</param>
442 public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY)
443 {
444 int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX;
445 int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY;
446
447 if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight)
448 {
449 // this region is included in the tile request
450 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
451 {
452 if (filename.EndsWith(loader.Key))
453 {
454 lock (m_scene)
455 {
456 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
457 fileWidth, fileHeight,
458 (int) Constants.RegionSize,
459 (int) Constants.RegionSize);
460 m_scene.Heightmap = channel;
461 m_channel = channel;
462 UpdateRevertMap();
463 }
464 return;
465 }
466 }
467 }
468 }
469
470 /// <summary>
471 /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections
472 /// </summary>
473 private void EventManager_OnTerrainTick()
474 {
475 if (m_tainted)
476 {
477 m_tainted = false;
478 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
479 m_scene.SaveTerrain();
480
481 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out.
482 //m_scene.CreateTerrainTexture(true);
483 }
484 }
485
486 /// <summary>
487 /// Processes commandline input. Do not call directly.
488 /// </summary>
489 /// <param name="args">Commandline arguments</param>
490 private void EventManager_OnPluginConsole(string[] args)
491 {
492 if (args[0] == "terrain")
493 {
494 if (args.Length == 1)
495 {
496 m_commander.ProcessConsoleCommand("help", new string[0]);
497 return;
498 }
499
500 string[] tmpArgs = new string[args.Length - 2];
501 int i;
502 for (i = 2; i < args.Length; i++)
503 tmpArgs[i - 2] = args[i];
504
505 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
506 }
507 }
508
509 /// <summary>
510 /// Installs terrain brush hook to IClientAPI
511 /// </summary>
512 /// <param name="client"></param>
513 private void EventManager_OnNewClient(IClientAPI client)
514 {
515 client.OnModifyTerrain += client_OnModifyTerrain;
516 client.OnBakeTerrain += client_OnBakeTerrain;
517 }
518
519 /// <summary>
520 /// Checks to see if the terrain has been modified since last check
521 /// but won't attempt to limit those changes to the limits specified in the estate settings
522 /// currently invoked by the command line operations in the region server only
523 /// </summary>
524 private void CheckForTerrainUpdates()
525 {
526 CheckForTerrainUpdates(false);
527 }
528
529 /// <summary>
530 /// Checks to see if the terrain has been modified since last check.
531 /// If it has been modified, every all the terrain patches are sent to the client.
532 /// If the call is asked to respect the estate settings for terrain_raise_limit and
533 /// terrain_lower_limit, it will clamp terrain updates between these values
534 /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces
535 /// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param>
536 /// </summary>
537 private void CheckForTerrainUpdates(bool respectEstateSettings)
538 {
539 bool shouldTaint = false;
540 float[] serialised = m_channel.GetFloatsSerialised();
541 int x;
542 for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize)
543 {
544 int y;
545 for (y = 0; y < m_channel.Height; y += Constants.TerrainPatchSize)
546 {
547 if (m_channel.Tainted(x, y))
548 {
549 // if we should respect the estate settings then
550 // fixup and height deltas that don't respect them
551 if (respectEstateSettings && LimitChannelChanges(x, y))
552 {
553 // this has been vetoed, so update
554 // what we are going to send to the client
555 serialised = m_channel.GetFloatsSerialised();
556 }
557
558 SendToClients(serialised, x, y);
559 shouldTaint = true;
560 }
561 }
562 }
563 if (shouldTaint)
564 {
565 m_tainted = true;
566 }
567 }
568
569 /// <summary>
570 /// Checks to see height deltas in the tainted terrain patch at xStart ,yStart
571 /// are all within the current estate limits
572 /// <returns>true if changes were limited, false otherwise</returns>
573 /// </summary>
574 private bool LimitChannelChanges(int xStart, int yStart)
575 {
576 bool changesLimited = false;
577 double minDelta = m_scene.RegionInfo.RegionSettings.TerrainLowerLimit;
578 double maxDelta = m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit;
579
580 // loop through the height map for this patch and compare it against
581 // the revert map
582 for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++)
583 {
584 for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
585 {
586
587 double requestedHeight = m_channel[x, y];
588 double bakedHeight = m_revert[x, y];
589 double requestedDelta = requestedHeight - bakedHeight;
590
591 if (requestedDelta > maxDelta)
592 {
593 m_channel[x, y] = bakedHeight + maxDelta;
594 changesLimited = true;
595 }
596 else if (requestedDelta < minDelta)
597 {
598 m_channel[x, y] = bakedHeight + minDelta; //as lower is a -ve delta
599 changesLimited = true;
600 }
601 }
602 }
603
604 return changesLimited;
605 }
606
607 /// <summary>
608 /// Sends a copy of the current terrain to the scenes clients
609 /// </summary>
610 /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param>
611 /// <param name="x">The patch corner to send</param>
612 /// <param name="y">The patch corner to send</param>
613 private void SendToClients(float[] serialised, int x, int y)
614 {
615 m_scene.ForEachClient(
616 delegate(IClientAPI controller)
617 { controller.SendLayerData(
618 x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised);
619 }
620 );
621 }
622
623 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action,
624 float north, float west, float south, float east, UUID agentId)
625 {
626 bool god = m_scene.Permissions.IsGod(user);
627 bool allowed = false;
628 if (north == south && east == west)
629 {
630 if (m_painteffects.ContainsKey((StandardTerrainEffects) action))
631 {
632 bool[,] allowMask = new bool[m_channel.Width,m_channel.Height];
633 allowMask.Initialize();
634 int n = size + 1;
635 if (n > 2)
636 n = 4;
637
638 int zx = (int) (west + 0.5);
639 int zy = (int) (north + 0.5);
640
641 int dx;
642 for (dx=-n; dx<=n; dx++)
643 {
644 int dy;
645 for (dy=-n; dy<=n; dy++)
646 {
647 int x = zx + dx;
648 int y = zy + dy;
649 if (x>=0 && y>=0 && x<m_channel.Width && y<m_channel.Height)
650 {
651 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0)))
652 {
653 allowMask[x, y] = true;
654 allowed = true;
655 }
656 }
657 }
658 }
659 if (allowed)
660 {
661 m_painteffects[(StandardTerrainEffects) action].PaintEffect(
662 m_channel, allowMask, west, south, height, size, seconds);
663
664 CheckForTerrainUpdates(!god); //revert changes outside estate limits
665 }
666 }
667 else
668 {
669 m_log.Debug("Unknown terrain brush type " + action);
670 }
671 }
672 else
673 {
674 if (m_floodeffects.ContainsKey((StandardTerrainEffects) action))
675 {
676 bool[,] fillArea = new bool[m_channel.Width,m_channel.Height];
677 fillArea.Initialize();
678
679 int x;
680 for (x = 0; x < m_channel.Width; x++)
681 {
682 int y;
683 for (y = 0; y < m_channel.Height; y++)
684 {
685 if (x < east && x > west)
686 {
687 if (y < north && y > south)
688 {
689 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0)))
690 {
691 fillArea[x, y] = true;
692 allowed = true;
693 }
694 }
695 }
696 }
697 }
698
699 if (allowed)
700 {
701 m_floodeffects[(StandardTerrainEffects) action].FloodEffect(
702 m_channel, fillArea, size);
703
704 CheckForTerrainUpdates(!god); //revert changes outside estate limits
705 }
706 }
707 else
708 {
709 m_log.Debug("Unknown terrain flood type " + action);
710 }
711 }
712 }
713
714 private void client_OnBakeTerrain(IClientAPI remoteClient)
715 {
716 // Not a good permissions check (see client_OnModifyTerrain above), need to check the entire area.
717 // for now check a point in the centre of the region
718
719 if (m_scene.Permissions.CanIssueEstateCommand(remoteClient.AgentId, true))
720 {
721 InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter
722 }
723 }
724
725 #region Console Commands
726
727 private void InterfaceLoadFile(Object[] args)
728 {
729 LoadFromFile((string) args[0]);
730 CheckForTerrainUpdates();
731 }
732
733 private void InterfaceLoadTileFile(Object[] args)
734 {
735 LoadFromFile((string) args[0],
736 (int) args[1],
737 (int) args[2],
738 (int) args[3],
739 (int) args[4]);
740 CheckForTerrainUpdates();
741 }
742
743 private void InterfaceSaveFile(Object[] args)
744 {
745 SaveToFile((string) args[0]);
746 }
747
748 private void InterfaceBakeTerrain(Object[] args)
749 {
750 UpdateRevertMap();
751 }
752
753 private void InterfaceRevertTerrain(Object[] args)
754 {
755 int x, y;
756 for (x = 0; x < m_channel.Width; x++)
757 for (y = 0; y < m_channel.Height; y++)
758 m_channel[x, y] = m_revert[x, y];
759
760 CheckForTerrainUpdates();
761 }
762
763 private void InterfaceFlipTerrain(Object[] args)
764 {
765 String direction = (String)args[0];
766
767 if (direction.ToLower().StartsWith("y"))
768 {
769 for (int x = 0; x < Constants.RegionSize; x++)
770 {
771 for (int y = 0; y < Constants.RegionSize / 2; y++)
772 {
773 double height = m_channel[x, y];
774 double flippedHeight = m_channel[x, (int)Constants.RegionSize - 1 - y];
775 m_channel[x, y] = flippedHeight;
776 m_channel[x, (int)Constants.RegionSize - 1 - y] = height;
777
778 }
779 }
780 }
781 else if (direction.ToLower().StartsWith("x"))
782 {
783 for (int y = 0; y < Constants.RegionSize; y++)
784 {
785 for (int x = 0; x < Constants.RegionSize / 2; x++)
786 {
787 double height = m_channel[x, y];
788 double flippedHeight = m_channel[(int)Constants.RegionSize - 1 - x, y];
789 m_channel[x, y] = flippedHeight;
790 m_channel[(int)Constants.RegionSize - 1 - x, y] = height;
791
792 }
793 }
794 }
795 else
796 {
797 m_log.Error("Unrecognised direction - need x or y");
798 }
799
800
801 CheckForTerrainUpdates();
802 }
803
804 private void InterfaceElevateTerrain(Object[] args)
805 {
806 int x, y;
807 for (x = 0; x < m_channel.Width; x++)
808 for (y = 0; y < m_channel.Height; y++)
809 m_channel[x, y] += (double) args[0];
810 CheckForTerrainUpdates();
811 }
812
813 private void InterfaceMultiplyTerrain(Object[] args)
814 {
815 int x, y;
816 for (x = 0; x < m_channel.Width; x++)
817 for (y = 0; y < m_channel.Height; y++)
818 m_channel[x, y] *= (double) args[0];
819 CheckForTerrainUpdates();
820 }
821
822 private void InterfaceLowerTerrain(Object[] args)
823 {
824 int x, y;
825 for (x = 0; x < m_channel.Width; x++)
826 for (y = 0; y < m_channel.Height; y++)
827 m_channel[x, y] -= (double) args[0];
828 CheckForTerrainUpdates();
829 }
830
831 private void InterfaceFillTerrain(Object[] args)
832 {
833 int x, y;
834
835 for (x = 0; x < m_channel.Width; x++)
836 for (y = 0; y < m_channel.Height; y++)
837 m_channel[x, y] = (double) args[0];
838 CheckForTerrainUpdates();
839 }
840
841 private void InterfaceShowDebugStats(Object[] args)
842 {
843 double max = Double.MinValue;
844 double min = double.MaxValue;
845 double sum = 0;
846
847 int x;
848 for (x = 0; x < m_channel.Width; x++)
849 {
850 int y;
851 for (y = 0; y < m_channel.Height; y++)
852 {
853 sum += m_channel[x, y];
854 if (max < m_channel[x, y])
855 max = m_channel[x, y];
856 if (min > m_channel[x, y])
857 min = m_channel[x, y];
858 }
859 }
860
861 double avg = sum / (m_channel.Height * m_channel.Width);
862
863 m_log.Info("Channel " + m_channel.Width + "x" + m_channel.Height);
864 m_log.Info("max/min/avg/sum: " + max + "/" + min + "/" + avg + "/" + sum);
865 }
866
867 private void InterfaceEnableExperimentalBrushes(Object[] args)
868 {
869 if ((bool) args[0])
870 {
871 m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere();
872 m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere();
873 m_painteffects[StandardTerrainEffects.Smooth] = new ErodeSphere();
874 }
875 else
876 {
877 InstallDefaultEffects();
878 }
879 }
880
881 private void InterfaceRunPluginEffect(Object[] args)
882 {
883 if ((string) args[0] == "list")
884 {
885 m_log.Info("List of loaded plugins");
886 foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects)
887 {
888 m_log.Info(kvp.Key);
889 }
890 return;
891 }
892 if ((string) args[0] == "reload")
893 {
894 LoadPlugins();
895 return;
896 }
897 if (m_plugineffects.ContainsKey((string) args[0]))
898 {
899 m_plugineffects[(string) args[0]].RunEffect(m_channel);
900 CheckForTerrainUpdates();
901 }
902 else
903 {
904 m_log.Warn("No such plugin effect loaded.");
905 }
906 }
907
908 private void InstallInterfaces()
909 {
910 // Load / Save
911 string supportedFileExtensions = "";
912 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
913 supportedFileExtensions += " " + loader.Key + " (" + loader.Value + ")";
914
915 Command loadFromFileCommand =
916 new Command("load", CommandIntentions.COMMAND_HAZARDOUS, InterfaceLoadFile, "Loads a terrain from a specified file.");
917 loadFromFileCommand.AddArgument("filename",
918 "The file you wish to load from, the file extension determines the loader to be used. Supported extensions include: " +
919 supportedFileExtensions, "String");
920
921 Command saveToFileCommand =
922 new Command("save", CommandIntentions.COMMAND_NON_HAZARDOUS, InterfaceSaveFile, "Saves the current heightmap to a specified file.");
923 saveToFileCommand.AddArgument("filename",
924 "The destination filename for your heightmap, the file extension determines the format to save in. Supported extensions include: " +
925 supportedFileExtensions, "String");
926
927 Command loadFromTileCommand =
928 new Command("load-tile", CommandIntentions.COMMAND_HAZARDOUS, InterfaceLoadTileFile, "Loads a terrain from a section of a larger file.");
929 loadFromTileCommand.AddArgument("filename",
930 "The file you wish to load from, the file extension determines the loader to be used. Supported extensions include: " +
931 supportedFileExtensions, "String");
932 loadFromTileCommand.AddArgument("file width", "The width of the file in tiles", "Integer");
933 loadFromTileCommand.AddArgument("file height", "The height of the file in tiles", "Integer");
934 loadFromTileCommand.AddArgument("minimum X tile", "The X region coordinate of the first section on the file",
935 "Integer");
936 loadFromTileCommand.AddArgument("minimum Y tile", "The Y region coordinate of the first section on the file",
937 "Integer");
938
939 // Terrain adjustments
940 Command fillRegionCommand =
941 new Command("fill", CommandIntentions.COMMAND_HAZARDOUS, InterfaceFillTerrain, "Fills the current heightmap with a specified value.");
942 fillRegionCommand.AddArgument("value", "The numeric value of the height you wish to set your region to.",
943 "Double");
944
945 Command elevateCommand =
946 new Command("elevate", CommandIntentions.COMMAND_HAZARDOUS, InterfaceElevateTerrain, "Raises the current heightmap by the specified amount.");
947 elevateCommand.AddArgument("amount", "The amount of height to add to the terrain in meters.", "Double");
948
949 Command lowerCommand =
950 new Command("lower", CommandIntentions.COMMAND_HAZARDOUS, InterfaceLowerTerrain, "Lowers the current heightmap by the specified amount.");
951 lowerCommand.AddArgument("amount", "The amount of height to remove from the terrain in meters.", "Double");
952
953 Command multiplyCommand =
954 new Command("multiply", CommandIntentions.COMMAND_HAZARDOUS, InterfaceMultiplyTerrain, "Multiplies the heightmap by the value specified.");
955 multiplyCommand.AddArgument("value", "The value to multiply the heightmap by.", "Double");
956
957 Command bakeRegionCommand =
958 new Command("bake", CommandIntentions.COMMAND_HAZARDOUS, InterfaceBakeTerrain, "Saves the current terrain into the regions revert map.");
959 Command revertRegionCommand =
960 new Command("revert", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRevertTerrain, "Loads the revert map terrain into the regions heightmap.");
961
962 Command flipCommand =
963 new Command("flip", CommandIntentions.COMMAND_HAZARDOUS, InterfaceFlipTerrain, "Flips the current terrain about the X or Y axis");
964 flipCommand.AddArgument("direction", "[x|y] the direction to flip the terrain in", "String");
965
966 // Debug
967 Command showDebugStatsCommand =
968 new Command("stats", CommandIntentions.COMMAND_STATISTICAL, InterfaceShowDebugStats,
969 "Shows some information about the regions heightmap for debugging purposes.");
970
971 Command experimentalBrushesCommand =
972 new Command("newbrushes", CommandIntentions.COMMAND_HAZARDOUS, InterfaceEnableExperimentalBrushes,
973 "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time.");
974 experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean");
975
976 //Plugins
977 Command pluginRunCommand =
978 new Command("effect", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRunPluginEffect, "Runs a specified plugin effect");
979 pluginRunCommand.AddArgument("name", "The plugin effect you wish to run, or 'list' to see all plugins", "String");
980
981 m_commander.RegisterCommand("load", loadFromFileCommand);
982 m_commander.RegisterCommand("load-tile", loadFromTileCommand);
983 m_commander.RegisterCommand("save", saveToFileCommand);
984 m_commander.RegisterCommand("fill", fillRegionCommand);
985 m_commander.RegisterCommand("elevate", elevateCommand);
986 m_commander.RegisterCommand("lower", lowerCommand);
987 m_commander.RegisterCommand("multiply", multiplyCommand);
988 m_commander.RegisterCommand("bake", bakeRegionCommand);
989 m_commander.RegisterCommand("revert", revertRegionCommand);
990 m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand);
991 m_commander.RegisterCommand("stats", showDebugStatsCommand);
992 m_commander.RegisterCommand("effect", pluginRunCommand);
993 m_commander.RegisterCommand("flip", flipCommand);
994
995 // Add this to our scene so scripts can call these functions
996 m_scene.RegisterModuleCommander(m_commander);
997 }
998
999 #endregion
1000 }
1001}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
new file mode 100644
index 0000000..e7f92d7
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
@@ -0,0 +1,118 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using OpenSim.Region.Framework.Scenes;
31using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
32
33namespace OpenSim.Region.CoreModules.World.Terrain.Tests
34{
35 [TestFixture]
36 public class TerrainTest
37 {
38 [Test]
39 public void BrushTest()
40 {
41 bool[,] allowMask = new bool[256, 256];
42 int x;
43 int y;
44 for (x=0; x<128; x++)
45 {
46 for (y=0; y<256; y++)
47 {
48 allowMask[x,y] = true;
49 }
50 }
51
52 //
53 // Test RaiseSphere
54 //
55 TerrainChannel map = new TerrainChannel(256, 256);
56 ITerrainPaintableEffect effect = new RaiseSphere();
57
58 effect.PaintEffect(map, allowMask, 128.0, 128.0, -1.0, 2, 0.1);
59 Assert.That(map[127, 128] > 0.0, "Raise brush should raising value at this point (127,128).");
60 Assert.That(map[124, 128] > 0.0, "Raise brush should raising value at this point (124,128).");
61 Assert.That(map[123, 128] == 0.0, "Raise brush should not change value at this point (123,128).");
62 Assert.That(map[128, 128] == 0.0, "Raise brush should not change value at this point (128,128).");
63 Assert.That(map[0, 128] == 0.0, "Raise brush should not change value at this point (0,128).");
64
65 //
66 // Test LowerSphere
67 //
68 map = new TerrainChannel(256, 256);
69 for (x=0; x<map.Width; x++)
70 {
71 for (y=0; y<map.Height; y++)
72 {
73 map[x,y] = 1.0;
74 }
75 }
76 effect = new LowerSphere();
77
78 effect.PaintEffect(map, allowMask, 128.0, 128.0, -1.0, 2, 6.0);
79 Assert.That(map[127, 128] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128).");
80 Assert.That(map[127, 128] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128).");
81 Assert.That(map[124, 128] < 1.0, "Lower brush should lowering value at this point (124,128).");
82 Assert.That(map[123, 128] == 1.0, "Lower brush should not change value at this point (123,128).");
83 Assert.That(map[128, 128] == 1.0, "Lower brush should not change value at this point (128,128).");
84 Assert.That(map[0, 128] == 1.0, "Lower brush should not change value at this point (0,128).");
85 }
86
87 [Test]
88 public void TerrainChannelTest()
89 {
90 TerrainChannel x = new TerrainChannel(256, 256);
91 Assert.That(x[0, 0] == 0.0, "Terrain not initialising correctly.");
92
93 x[0, 0] = 1.0;
94 Assert.That(x[0, 0] == 1.0, "Terrain not setting values correctly.");
95
96 x[0, 0] = 0;
97 x[0, 0] += 5.0;
98 x[0, 0] -= 1.0;
99 Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error.");
100
101 x[0, 0] = Math.PI;
102 double[,] doublesExport = x.GetDoubles();
103 Assert.That(doublesExport[0, 0] == Math.PI, "Export to double[,] array not working correctly.");
104
105 x[0, 0] = 1.0;
106 float[] floatsExport = x.GetFloatsSerialised();
107 Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly.");
108
109 x[0, 0] = 1.0;
110 Assert.That(x.Tainted(0, 0), "Terrain channel tainting not working correctly.");
111 Assert.That(!x.Tainted(0, 0), "Terrain channel tainting not working correctly.");
112
113 TerrainChannel y = x.Copy();
114 Assert.That(!ReferenceEquals(x, y), "Terrain copy not duplicating correctly.");
115 Assert.That(!ReferenceEquals(x.GetDoubles(), y.GetDoubles()), "Terrain array not duplicating correctly.");
116 }
117 }
118}
diff --git a/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs
new file mode 100644
index 0000000..8b2bb1e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs
@@ -0,0 +1,118 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using log4net;
31using Nini.Config;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.CoreModules.Avatar.Vegetation
40{
41 public class VegetationModule : IRegionModule, IVegetationModule
42 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 protected Scene m_scene;
46
47 protected static readonly PCode[] creationCapabilities = new PCode[] { PCode.Grass, PCode.NewTree, PCode.Tree };
48 public PCode[] CreationCapabilities { get { return creationCapabilities; } }
49
50 public void Initialise(Scene scene, IConfigSource source)
51 {
52 m_scene = scene;
53 m_scene.RegisterModuleInterface<IVegetationModule>(this);
54 }
55
56 public void PostInitialise() {}
57 public void Close() {}
58 public string Name { get { return "Vegetation Module"; } }
59 public bool IsSharedModule { get { return false; } }
60
61 public SceneObjectGroup AddTree(
62 UUID uuid, UUID groupID, Vector3 scale, Quaternion rotation, Vector3 position, Tree treeType, bool newTree)
63 {
64 PrimitiveBaseShape treeShape = new PrimitiveBaseShape();
65 treeShape.PathCurve = 16;
66 treeShape.PathEnd = 49900;
67 treeShape.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree;
68 treeShape.Scale = scale;
69 treeShape.State = (byte)treeType;
70
71 return m_scene.AddNewPrim(uuid, groupID, position, rotation, treeShape);
72 }
73
74 public SceneObjectGroup CreateEntity(
75 UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
76 {
77 if (Array.IndexOf(creationCapabilities, (PCode)shape.PCode) < 0)
78 {
79 m_log.DebugFormat("[VEGETATION]: PCode {0} not handled by {1}", shape.PCode, Name);
80 return null;
81 }
82
83 SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
84 SceneObjectPart rootPart = sceneObject.GetChildPart(sceneObject.UUID);
85
86 // if grass or tree, make phantom
87 //rootPart.TrimPermissions();
88 rootPart.AddFlag(PrimFlags.Phantom);
89 if (rootPart.Shape.PCode != (byte)PCode.Grass)
90 AdaptTree(ref shape);
91
92 m_scene.AddNewSceneObject(sceneObject, true);
93 sceneObject.SetGroup(groupID, null);
94
95 return sceneObject;
96 }
97
98 protected void AdaptTree(ref PrimitiveBaseShape tree)
99 {
100 // Tree size has to be adapted depending on its type
101 switch ((Tree)tree.State)
102 {
103 case Tree.Cypress1:
104 case Tree.Cypress2:
105 tree.Scale = new Vector3(4, 4, 10);
106 break;
107
108 // case... other tree types
109 // tree.Scale = new Vector3(?, ?, ?);
110 // break;
111
112 default:
113 tree.Scale = new Vector3(4, 4, 4);
114 break;
115 }
116 }
117 }
118}
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
new file mode 100644
index 0000000..b8bd605
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
@@ -0,0 +1,207 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.CoreModules
37{
38 public class WindModule : IWindModule
39 {
40// private static readonly log4net.ILog m_log
41// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
42
43 private int m_frame = 0;
44 private int m_frame_mod = 150;
45 private Random rndnums = new Random(System.Environment.TickCount);
46 private Scene m_scene = null;
47 private bool ready = false;
48 private Vector2[] windSpeeds = new Vector2[16 * 16];
49 private Dictionary<UUID, ulong> m_rootAgents = new Dictionary<UUID, ulong>();
50
51 public void Initialise(Scene scene, IConfigSource config)
52 {
53 m_scene = scene;
54 m_frame = 0;
55
56 scene.EventManager.OnFrame += WindUpdate;
57 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
58 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
59 scene.EventManager.OnClientClosed += ClientLoggedOut;
60 scene.RegisterModuleInterface<IWindModule>(this);
61
62 GenWindPos();
63
64 ready = true;
65 }
66
67 public void PostInitialise()
68 {
69 }
70
71 public void Close()
72 {
73 ready = false;
74 // Remove our hooks
75 m_scene.EventManager.OnFrame -= WindUpdate;
76 // m_scene.EventManager.OnNewClient -= SunToClient;
77 m_scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
78 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel;
79 m_scene.EventManager.OnClientClosed -= ClientLoggedOut;
80 }
81
82 public string Name
83 {
84 get { return "WindModule"; }
85 }
86
87 public bool IsSharedModule
88 {
89 get { return false; }
90 }
91
92 public Vector2[] WindSpeeds
93 {
94 get { return windSpeeds; }
95 }
96
97 public void WindToClient(IClientAPI client)
98 {
99 if (ready)
100 {
101 //if (!sunFixed)
102 //GenWindPos(); // Generate shared values once
103 client.SendWindData(windSpeeds);
104 }
105 }
106
107 public void WindUpdate()
108 {
109 if (((m_frame++ % m_frame_mod) != 0) || !ready)
110 {
111 return;
112 }
113 //m_log.Debug("[WIND]:Regenerating...");
114 GenWindPos(); // Generate shared values once
115
116 //int spotxp = 0;
117 //int spotyp = 0;
118 //int spotxm = 0;
119 //int spotym = 0;
120 List<ScenePresence> avatars = m_scene.GetAvatars();
121 foreach (ScenePresence avatar in avatars)
122 {
123 if (!avatar.IsChildAgent)
124 {
125 avatar.ControllingClient.SendWindData(windSpeeds);
126 }
127 }
128
129 // set estate settings for region access to sun position
130 //m_scene.RegionInfo.RegionSettings.SunVector = Position;
131 //m_scene.RegionInfo.EstateSettings.sunHour = GetLindenEstateHourFromCurrentTime();
132 }
133
134 public void ForceWindUpdateToAllClients()
135 {
136 GenWindPos(); // Generate shared values once
137
138 List<ScenePresence> avatars = m_scene.GetAvatars();
139 foreach (ScenePresence avatar in avatars)
140 {
141 if (!avatar.IsChildAgent)
142 avatar.ControllingClient.SendWindData(windSpeeds);
143 }
144
145 // set estate settings for region access to sun position
146 //m_scene.RegionInfo.RegionSettings.SunVector = Position;
147 //m_scene.RegionInfo.RegionSettings.SunPosition = GetLindenEstateHourFromCurrentTime();
148 }
149 /// <summary>
150 /// Calculate the sun's orbital position and its velocity.
151 /// </summary>
152
153 private void GenWindPos()
154 {
155 for (int y = 0; y < 16; y++)
156 {
157 for (int x = 0; x < 16; x++)
158 {
159 windSpeeds[y * 16 + x].X = (float)(rndnums.NextDouble() * 2d - 1d);
160 windSpeeds[y * 16 + x].Y = (float)(rndnums.NextDouble() * 2d - 1d);
161 }
162 }
163 }
164
165 private void ClientLoggedOut(UUID AgentId)
166 {
167 lock (m_rootAgents)
168 {
169 if (m_rootAgents.ContainsKey(AgentId))
170 {
171 m_rootAgents.Remove(AgentId);
172 }
173 }
174 }
175
176 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
177 {
178 lock (m_rootAgents)
179 {
180 if (m_rootAgents.ContainsKey(avatar.UUID))
181 {
182 m_rootAgents[avatar.UUID] = avatar.RegionHandle;
183 }
184 else
185 {
186 m_rootAgents.Add(avatar.UUID, avatar.RegionHandle);
187 WindToClient(avatar.ControllingClient);
188 }
189 }
190 //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString());
191 }
192
193 private void MakeChildAgent(ScenePresence avatar)
194 {
195 lock (m_rootAgents)
196 {
197 if (m_rootAgents.ContainsKey(avatar.UUID))
198 {
199 if (m_rootAgents[avatar.UUID] == avatar.RegionHandle)
200 {
201 m_rootAgents.Remove(avatar.UUID);
202 }
203 }
204 }
205 }
206 }
207}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs b/OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs
new file mode 100644
index 0000000..3684df0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/IMapTileTerrainRenderer.cs
@@ -0,0 +1,39 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Drawing;
29using OpenSim.Region.Framework.Scenes;
30using Nini.Config;
31
32namespace OpenSim.Region.CoreModules.World.WorldMap
33{
34 public interface IMapTileTerrainRenderer
35 {
36 void Initialise(Scene scene, IConfigSource config);
37 void TerrainToBitmap(Bitmap mapbmp);
38 }
39}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs
new file mode 100644
index 0000000..eea6cf6
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs
@@ -0,0 +1,586 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Drawing2D;
33using System.Drawing.Imaging;
34using System.Reflection;
35using Nini.Config;
36using OpenMetaverse.Imaging;
37using log4net;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenMetaverse;
41
42namespace OpenSim.Region.CoreModules.World.WorldMap
43{
44 public enum DrawRoutine
45 {
46 Rectangle,
47 Polygon,
48 Ellipse
49 }
50
51 public struct face
52 {
53 public Point[] pts;
54 }
55
56 public struct DrawStruct
57 {
58 public DrawRoutine dr;
59 public Rectangle rect;
60 public SolidBrush brush;
61 public face[] trns;
62 }
63
64 public class MapImageModule : IMapImageGenerator, IRegionModule
65 {
66 private static readonly ILog m_log =
67 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 private Scene m_scene;
70 private IConfigSource m_config;
71 private IMapTileTerrainRenderer terrainRenderer;
72
73 #region IMapImageGenerator Members
74
75 public byte[] WriteJpeg2000Image(string gradientmap)
76 {
77 byte[] imageData = null;
78
79 bool drawPrimVolume = true;
80 bool textureTerrain = true;
81
82 try
83 {
84 IConfig startupConfig = m_config.Configs["Startup"];
85 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume);
86 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain);
87 }
88 catch
89 {
90 m_log.Warn("[MAPTILE]: Failed to load StartupConfig");
91 }
92
93 if (textureTerrain)
94 {
95 terrainRenderer = new TexturedMapTileRenderer();
96 }
97 else
98 {
99 terrainRenderer = new ShadedMapTileRenderer();
100 }
101 terrainRenderer.Initialise(m_scene, m_config);
102
103 Bitmap mapbmp = new Bitmap(256, 256);
104 //long t = System.Environment.TickCount;
105 //for (int i = 0; i < 10; ++i) {
106 terrainRenderer.TerrainToBitmap(mapbmp);
107 //}
108 //t = System.Environment.TickCount - t;
109 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t);
110
111
112 if (drawPrimVolume)
113 {
114 DrawObjectVolume(m_scene, mapbmp);
115 }
116
117 try
118 {
119 imageData = OpenJPEG.EncodeFromImage(mapbmp, true);
120 }
121 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
122 {
123 Console.WriteLine("Failed generating terrain map: " + e);
124 }
125
126 return imageData;
127 }
128
129 #endregion
130
131 #region IRegionModule Members
132
133 public void Initialise(Scene scene, IConfigSource source)
134 {
135 m_scene = scene;
136 m_config = source;
137
138 IConfig startupConfig = m_config.Configs["Startup"];
139 if (startupConfig.GetString("MapImageModule", "MapImageModule") !=
140 "MapImageModule")
141 return;
142
143 m_scene.RegisterModuleInterface<IMapImageGenerator>(this);
144 }
145
146 public void PostInitialise()
147 {
148 }
149
150 public void Close()
151 {
152 }
153
154 public string Name
155 {
156 get { return "MapImageModule"; }
157 }
158
159 public bool IsSharedModule
160 {
161 get { return false; }
162 }
163
164 #endregion
165
166// TODO: unused:
167// private void ShadeBuildings(Bitmap map)
168// {
169// lock (map)
170// {
171// lock (m_scene.Entities)
172// {
173// foreach (EntityBase entity in m_scene.Entities.Values)
174// {
175// if (entity is SceneObjectGroup)
176// {
177// SceneObjectGroup sog = (SceneObjectGroup) entity;
178//
179// foreach (SceneObjectPart primitive in sog.Children.Values)
180// {
181// int x = (int) (primitive.AbsolutePosition.X - (primitive.Scale.X / 2));
182// int y = (int) (primitive.AbsolutePosition.Y - (primitive.Scale.Y / 2));
183// int w = (int) primitive.Scale.X;
184// int h = (int) primitive.Scale.Y;
185//
186// int dx;
187// for (dx = x; dx < x + w; dx++)
188// {
189// int dy;
190// for (dy = y; dy < y + h; dy++)
191// {
192// if (x < 0 || y < 0)
193// continue;
194// if (x >= map.Width || y >= map.Height)
195// continue;
196//
197// map.SetPixel(dx, dy, Color.DarkGray);
198// }
199// }
200// }
201// }
202// }
203// }
204// }
205// }
206
207 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
208 {
209 int tc = 0;
210 double[,] hm = whichScene.Heightmap.GetDoubles();
211 tc = System.Environment.TickCount;
212 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
213 List<EntityBase> objs = whichScene.GetEntities();
214 Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
215 //SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>();
216 List<float> z_sortheights = new List<float>();
217 List<uint> z_localIDs = new List<uint>();
218
219 lock (objs)
220 {
221 foreach (EntityBase obj in objs)
222 {
223 // Only draw the contents of SceneObjectGroup
224 if (obj is SceneObjectGroup)
225 {
226 SceneObjectGroup mapdot = (SceneObjectGroup)obj;
227 Color mapdotspot = Color.Gray; // Default color when prim color is white
228 // Loop over prim in group
229 foreach (SceneObjectPart part in mapdot.Children.Values)
230 {
231 if (part == null)
232 continue;
233
234 // Draw if the object is at least 1 meter wide in any direction
235 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
236 {
237 // Try to get the RGBA of the default texture entry..
238 //
239 try
240 {
241 // get the null checks out of the way
242 // skip the ones that break
243 if (part == null)
244 continue;
245
246 if (part.Shape == null)
247 continue;
248
249 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
250 continue; // eliminates trees from this since we don't really have a good tree representation
251 // if you want tree blocks on the map comment the above line and uncomment the below line
252 //mapdotspot = Color.PaleGreen;
253
254 if (part.Shape.Textures == null)
255 continue;
256
257 if (part.Shape.Textures.DefaultTexture == null)
258 continue;
259
260 Color4 texcolor = part.Shape.Textures.DefaultTexture.RGBA;
261
262 // Not sure why some of these are null, oh well.
263
264 int colorr = 255 - (int)(texcolor.R * 255f);
265 int colorg = 255 - (int)(texcolor.G * 255f);
266 int colorb = 255 - (int)(texcolor.B * 255f);
267
268 if (!(colorr == 255 && colorg == 255 && colorb == 255))
269 {
270 //Try to set the map spot color
271 try
272 {
273 // If the color gets goofy somehow, skip it *shakes fist at Color4
274 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
275 }
276 catch (ArgumentException)
277 {
278 }
279 }
280 }
281 catch (IndexOutOfRangeException)
282 {
283 // Windows Array
284 }
285 catch (ArgumentOutOfRangeException)
286 {
287 // Mono Array
288 }
289
290 Vector3 pos = part.GetWorldPosition();
291
292 // skip prim outside of retion
293 if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
294 continue;
295
296 // skip prim in non-finite position
297 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
298 Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
299 continue;
300
301 // Figure out if object is under 256m above the height of the terrain
302 bool isBelow256AboveTerrain = false;
303
304 try
305 {
306 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
307 }
308 catch (Exception)
309 {
310 }
311
312 if (isBelow256AboveTerrain)
313 {
314 // Translate scale by rotation so scale is represented properly when object is rotated
315 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
316 Vector3 scale = new Vector3();
317 Vector3 tScale = new Vector3();
318 Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
319
320 Quaternion llrot = part.GetWorldRotation();
321 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
322 scale = lscale * rot;
323
324 // negative scales don't work in this situation
325 scale.X = Math.Abs(scale.X);
326 scale.Y = Math.Abs(scale.Y);
327 scale.Z = Math.Abs(scale.Z);
328
329 // This scaling isn't very accurate and doesn't take into account the face rotation :P
330 int mapdrawstartX = (int)(pos.X - scale.X);
331 int mapdrawstartY = (int)(pos.Y - scale.Y);
332 int mapdrawendX = (int)(pos.X + scale.X);
333 int mapdrawendY = (int)(pos.Y + scale.Y);
334
335 // If object is beyond the edge of the map, don't draw it to avoid errors
336 if (mapdrawstartX < 0 || mapdrawstartX > 255 || mapdrawendX < 0 || mapdrawendX > 255
337 || mapdrawstartY < 0 || mapdrawstartY > 255 || mapdrawendY < 0
338 || mapdrawendY > 255)
339 continue;
340
341#region obb face reconstruction part duex
342 Vector3[] vertexes = new Vector3[8];
343
344 // float[] distance = new float[6];
345 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
346 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
347 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
348 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
349
350 tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
351 scale = ((tScale * rot));
352 vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
353 // vertexes[0].x = pos.X + vertexes[0].x;
354 //vertexes[0].y = pos.Y + vertexes[0].y;
355 //vertexes[0].z = pos.Z + vertexes[0].z;
356
357 FaceA[0] = vertexes[0];
358 FaceB[3] = vertexes[0];
359 FaceA[4] = vertexes[0];
360
361 tScale = lscale;
362 scale = ((tScale * rot));
363 vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
364
365 // vertexes[1].x = pos.X + vertexes[1].x;
366 // vertexes[1].y = pos.Y + vertexes[1].y;
367 //vertexes[1].z = pos.Z + vertexes[1].z;
368
369 FaceB[0] = vertexes[1];
370 FaceA[1] = vertexes[1];
371 FaceC[4] = vertexes[1];
372
373 tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
374 scale = ((tScale * rot));
375
376 vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
377
378 //vertexes[2].x = pos.X + vertexes[2].x;
379 //vertexes[2].y = pos.Y + vertexes[2].y;
380 //vertexes[2].z = pos.Z + vertexes[2].z;
381
382 FaceC[0] = vertexes[2];
383 FaceD[3] = vertexes[2];
384 FaceC[5] = vertexes[2];
385
386 tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
387 scale = ((tScale * rot));
388 vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
389
390 //vertexes[3].x = pos.X + vertexes[3].x;
391 // vertexes[3].y = pos.Y + vertexes[3].y;
392 // vertexes[3].z = pos.Z + vertexes[3].z;
393
394 FaceD[0] = vertexes[3];
395 FaceC[1] = vertexes[3];
396 FaceA[5] = vertexes[3];
397
398 tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
399 scale = ((tScale * rot));
400 vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
401
402 // vertexes[4].x = pos.X + vertexes[4].x;
403 // vertexes[4].y = pos.Y + vertexes[4].y;
404 // vertexes[4].z = pos.Z + vertexes[4].z;
405
406 FaceB[1] = vertexes[4];
407 FaceA[2] = vertexes[4];
408 FaceD[4] = vertexes[4];
409
410 tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
411 scale = ((tScale * rot));
412 vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
413
414 // vertexes[5].x = pos.X + vertexes[5].x;
415 // vertexes[5].y = pos.Y + vertexes[5].y;
416 // vertexes[5].z = pos.Z + vertexes[5].z;
417
418 FaceD[1] = vertexes[5];
419 FaceC[2] = vertexes[5];
420 FaceB[5] = vertexes[5];
421
422 tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
423 scale = ((tScale * rot));
424 vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
425
426 // vertexes[6].x = pos.X + vertexes[6].x;
427 // vertexes[6].y = pos.Y + vertexes[6].y;
428 // vertexes[6].z = pos.Z + vertexes[6].z;
429
430 FaceB[2] = vertexes[6];
431 FaceA[3] = vertexes[6];
432 FaceB[4] = vertexes[6];
433
434 tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
435 scale = ((tScale * rot));
436 vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
437
438 // vertexes[7].x = pos.X + vertexes[7].x;
439 // vertexes[7].y = pos.Y + vertexes[7].y;
440 // vertexes[7].z = pos.Z + vertexes[7].z;
441
442 FaceD[2] = vertexes[7];
443 FaceC[3] = vertexes[7];
444 FaceD[5] = vertexes[7];
445#endregion
446
447 //int wy = 0;
448
449 //bool breakYN = false; // If we run into an error drawing, break out of the
450 // loop so we don't lag to death on error handling
451 DrawStruct ds = new DrawStruct();
452 ds.brush = new SolidBrush(mapdotspot);
453 //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
454
455 ds.trns = new face[FaceA.Length];
456
457 for (int i = 0; i < FaceA.Length; i++)
458 {
459 Point[] working = new Point[5];
460 working[0] = project(FaceA[i], axPos);
461 working[1] = project(FaceB[i], axPos);
462 working[2] = project(FaceD[i], axPos);
463 working[3] = project(FaceC[i], axPos);
464 working[4] = project(FaceA[i], axPos);
465
466 face workingface = new face();
467 workingface.pts = working;
468
469 ds.trns[i] = workingface;
470 }
471
472 z_sort.Add(part.LocalId, ds);
473 z_localIDs.Add(part.LocalId);
474 z_sortheights.Add(pos.Z);
475
476 //for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
477 //{
478 //for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
479 //{
480 //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
481 //try
482 //{
483 // Remember, flip the y!
484 // mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
485 //}
486 //catch (ArgumentException)
487 //{
488 // breakYN = true;
489 //}
490
491 //if (breakYN)
492 // break;
493 //}
494
495 //if (breakYN)
496 // break;
497 //}
498 } // Object is within 256m Z of terrain
499 } // object is at least a meter wide
500 } // loop over group children
501 } // entitybase is sceneobject group
502 } // foreach loop over entities
503
504 float[] sortedZHeights = z_sortheights.ToArray();
505 uint[] sortedlocalIds = z_localIDs.ToArray();
506
507 // Sort prim by Z position
508 Array.Sort(sortedZHeights, sortedlocalIds);
509
510 Graphics g = Graphics.FromImage(mapbmp);
511
512 for (int s = 0; s < sortedZHeights.Length; s++)
513 {
514 if (z_sort.ContainsKey(sortedlocalIds[s]))
515 {
516 DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]];
517 for (int r = 0; r < rectDrawStruct.trns.Length; r++ )
518 {
519 g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts);
520 }
521 //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
522 }
523 }
524
525 g.Dispose();
526 } // lock entities objs
527
528 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Done in " + (System.Environment.TickCount - tc) + " ms");
529 return mapbmp;
530 }
531
532 private Point project(Vector3 point3d, Vector3 originpos)
533 {
534 Point returnpt = new Point();
535 //originpos = point3d;
536 //int d = (int)(256f / 1.5f);
537
538 //Vector3 topos = new Vector3(0, 0, 0);
539 // float z = -point3d.z - topos.z;
540
541 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d);
542 returnpt.Y = (int)(255 - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d)));
543
544 return returnpt;
545 }
546
547// TODO: unused:
548// #region Deprecated Maptile Generation. Adam may update this
549// private Bitmap TerrainToBitmap(string gradientmap)
550// {
551// Bitmap gradientmapLd = new Bitmap(gradientmap);
552//
553// int pallete = gradientmapLd.Height;
554//
555// Bitmap bmp = new Bitmap(m_scene.Heightmap.Width, m_scene.Heightmap.Height);
556// Color[] colours = new Color[pallete];
557//
558// for (int i = 0; i < pallete; i++)
559// {
560// colours[i] = gradientmapLd.GetPixel(0, i);
561// }
562//
563// lock (m_scene.Heightmap)
564// {
565// ITerrainChannel copy = m_scene.Heightmap;
566// for (int y = 0; y < copy.Height; y++)
567// {
568// for (int x = 0; x < copy.Width; x++)
569// {
570// // 512 is the largest possible height before colours clamp
571// int colorindex = (int) (Math.Max(Math.Min(1.0, copy[x, y] / 512.0), 0.0) * (pallete - 1));
572//
573// // Handle error conditions
574// if (colorindex > pallete - 1 || colorindex < 0)
575// bmp.SetPixel(x, copy.Height - y - 1, Color.Red);
576// else
577// bmp.SetPixel(x, copy.Height - y - 1, colours[colorindex]);
578// }
579// }
580// ShadeBuildings(bmp);
581// return bmp;
582// }
583// }
584// #endregion
585 }
586}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
new file mode 100644
index 0000000..45a99a9
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -0,0 +1,172 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Reflection;
29using System.Collections.Generic;
30using System.Net;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.Framework.Scenes.Hypergrid;
35using OpenMetaverse;
36using log4net;
37using Nini.Config;
38
39namespace OpenSim.Region.CoreModules.World.WorldMap
40{
41 public class MapSearchModule : IRegionModule
42 {
43 private static readonly ILog m_log =
44 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 Scene m_scene = null; // only need one for communication with GridService
47 List<Scene> m_scenes = new List<Scene>();
48
49 #region IRegionModule Members
50 public void Initialise(Scene scene, IConfigSource source)
51 {
52 if (m_scene == null)
53 {
54 m_scene = scene;
55 }
56
57 m_scenes.Add(scene);
58 scene.EventManager.OnNewClient += OnNewClient;
59 }
60
61 public void PostInitialise()
62 {
63 }
64
65 public void Close()
66 {
67 m_scene = null;
68 m_scenes.Clear();
69 }
70
71 public string Name
72 {
73 get { return "MapSearchModule"; }
74 }
75
76 public bool IsSharedModule
77 {
78 get { return true; }
79 }
80
81 #endregion
82
83 private void OnNewClient(IClientAPI client)
84 {
85 client.OnMapNameRequest += OnMapNameRequest;
86 }
87
88 private void OnMapNameRequest(IClientAPI remoteClient, string mapName)
89 {
90 if (mapName.Length < 3)
91 {
92 remoteClient.SendAlertMessage("Use a search string with at least 3 characters");
93 return;
94 }
95
96 // try to fetch from GridServer
97 List<RegionInfo> regionInfos = m_scene.SceneGridService.RequestNamedRegions(mapName, 20);
98 if (regionInfos == null)
99 {
100 m_log.Warn("[MAPSEARCHMODULE]: RequestNamedRegions returned null. Old gridserver?");
101 // service wasn't available; maybe still an old GridServer. Try the old API, though it will return only one region
102 regionInfos = new List<RegionInfo>();
103 RegionInfo info = m_scene.SceneGridService.RequestClosestRegion(mapName);
104 if (info != null) regionInfos.Add(info);
105 }
106
107 if ((regionInfos.Count == 0) && IsHypergridOn())
108 {
109 // OK, we tried but there are no regions matching that name.
110 // Let's check quickly if this is a domain name, and if so link to it
111 if (mapName.Contains(".") && mapName.Contains(":"))
112 {
113 // It probably is a domain name. Try to link to it.
114 RegionInfo regInfo;
115 Scene cScene = GetClientScene(remoteClient);
116 regInfo = HGHyperlink.TryLinkRegion(cScene, remoteClient, mapName);
117 if (regInfo != null)
118 regionInfos.Add(regInfo);
119 }
120 }
121
122 List<MapBlockData> blocks = new List<MapBlockData>();
123
124 MapBlockData data;
125 if (regionInfos.Count > 0)
126 {
127 foreach (RegionInfo info in regionInfos)
128 {
129 data = new MapBlockData();
130 data.Agents = 0;
131 data.Access = 21; // TODO what's this?
132 data.MapImageId = info.RegionSettings.TerrainImageID;
133 data.Name = info.RegionName;
134 data.RegionFlags = 0; // TODO not used?
135 data.WaterHeight = 0; // not used
136 data.X = (ushort)info.RegionLocX;
137 data.Y = (ushort)info.RegionLocY;
138 blocks.Add(data);
139 }
140 }
141
142 // final block, closing the search result
143 data = new MapBlockData();
144 data.Agents = 0;
145 data.Access = 255;
146 data.MapImageId = UUID.Zero;
147 data.Name = mapName;
148 data.RegionFlags = 0;
149 data.WaterHeight = 0; // not used
150 data.X = 0;
151 data.Y = 0;
152 blocks.Add(data);
153
154 remoteClient.SendMapBlock(blocks, 0);
155 }
156
157 private bool IsHypergridOn()
158 {
159 return (m_scene.SceneGridService is HGSceneCommunicationService);
160 }
161
162 private Scene GetClientScene(IClientAPI client)
163 {
164 foreach (Scene s in m_scenes)
165 {
166 if (client.Scene.RegionInfo.RegionHandle == s.RegionInfo.RegionHandle)
167 return s;
168 }
169 return m_scene;
170 }
171 }
172}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs
new file mode 100644
index 0000000..b783d7c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/ShadedMapTileRenderer.cs
@@ -0,0 +1,249 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Drawing2D;
33using System.Drawing.Imaging;
34using System.Reflection;
35using OpenMetaverse;
36using OpenMetaverse.Imaging;
37using Nini.Config;
38using log4net;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.World.WorldMap
43{
44 public class ShadedMapTileRenderer : IMapTileTerrainRenderer
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private Scene m_scene;
50 //private IConfigSource m_config; // not used currently
51
52 public void Initialise(Scene scene, IConfigSource config)
53 {
54 m_scene = scene;
55 // m_config = config; // not used currently
56 }
57
58 public void TerrainToBitmap(Bitmap mapbmp)
59 {
60 int tc = System.Environment.TickCount;
61 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");
62
63 double[,] hm = m_scene.Heightmap.GetDoubles();
64 bool ShadowDebugContinue = true;
65
66 bool terraincorruptedwarningsaid = false;
67
68 float low = 255;
69 float high = 0;
70 for (int x = 0; x < 256; x++)
71 {
72 for (int y = 0; y < 256; y++)
73 {
74 float hmval = (float)hm[x, y];
75 if (hmval < low)
76 low = hmval;
77 if (hmval > high)
78 high = hmval;
79 }
80 }
81
82 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
83
84 for (int x = 0; x < 256; x++)
85 {
86 for (int y = 0; y < 256; y++)
87 {
88 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
89 int yr = 255 - y;
90
91 float heightvalue = (float)hm[x, y];
92
93 if (heightvalue > waterHeight)
94 {
95 // scale height value
96 // No, that doesn't scale it:
97 // heightvalue = low + mid * (heightvalue - low) / mid; => low + (heightvalue - low) * mid / mid = low + (heightvalue - low) * 1 = low + heightvalue - low = heightvalue
98
99 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
100 heightvalue = 0;
101 else if (heightvalue > 255f)
102 heightvalue = 255f;
103 else if (heightvalue < 0f)
104 heightvalue = 0f;
105
106 Color color = Color.FromArgb((int)heightvalue, 100, (int)heightvalue);
107
108 mapbmp.SetPixel(x, yr, color);
109
110 try
111 {
112 //X
113 // .
114 //
115 // Shade the terrain for shadows
116 if (x < 255 && yr < 255)
117 {
118 float hfvalue = (float)hm[x, y];
119 float hfvaluecompare = 0f;
120
121 if ((x + 1 < 256) && (y + 1 < 256))
122 {
123 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there
124 }
125 if (Single.IsInfinity(hfvalue) || Single.IsNaN(hfvalue))
126 hfvalue = 0f;
127
128 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
129 hfvaluecompare = 0f;
130
131 float hfdiff = hfvalue - hfvaluecompare; // => positive if NE is lower, negative if here is lower
132
133 int hfdiffi = 0;
134 int hfdiffihighlight = 0;
135 float highlightfactor = 0.18f;
136
137 try
138 {
139 // hfdiffi = Math.Abs((int)((hfdiff * 4) + (hfdiff * 0.5))) + 1;
140 hfdiffi = Math.Abs((int)(hfdiff * 4.5f)) + 1;
141 if (hfdiff % 1f != 0)
142 {
143 // hfdiffi = hfdiffi + Math.Abs((int)(((hfdiff % 1) * 0.5f) * 10f) - 1);
144 hfdiffi = hfdiffi + Math.Abs((int)((hfdiff % 1f) * 5f) - 1);
145 }
146
147 hfdiffihighlight = Math.Abs((int)((hfdiff * highlightfactor) * 4.5f)) + 1;
148 if (hfdiff % 1f != 0)
149 {
150 // hfdiffi = hfdiffi + Math.Abs((int)(((hfdiff % 1) * 0.5f) * 10f) - 1);
151 hfdiffihighlight = hfdiffihighlight + Math.Abs((int)(((hfdiff * highlightfactor) % 1f) * 5f) - 1);
152 }
153 }
154 catch (System.OverflowException)
155 {
156 m_log.Debug("[MAPTILE]: Shadow failed at value: " + hfdiff.ToString());
157 ShadowDebugContinue = false;
158 }
159
160 if (hfdiff > 0.3f)
161 {
162 // NE is lower than here
163 // We have to desaturate and lighten the land at the same time
164 // we use floats, colors use bytes, so shrink are space down to
165 // 0-255
166
167 if (ShadowDebugContinue)
168 {
169 int r = color.R;
170 int g = color.G;
171 int b = color.B;
172 color = Color.FromArgb((r + hfdiffihighlight < 255) ? r + hfdiffihighlight : 255,
173 (g + hfdiffihighlight < 255) ? g + hfdiffihighlight : 255,
174 (b + hfdiffihighlight < 255) ? b + hfdiffihighlight : 255);
175 }
176 }
177 else if (hfdiff < -0.3f)
178 {
179 // here is lower than NE:
180 // We have to desaturate and blacken the land at the same time
181 // we use floats, colors use bytes, so shrink are space down to
182 // 0-255
183
184 if (ShadowDebugContinue)
185 {
186 if ((x - 1 > 0) && (yr + 1 < 256))
187 {
188 color = mapbmp.GetPixel(x - 1, yr + 1);
189 int r = color.R;
190 int g = color.G;
191 int b = color.B;
192 color = Color.FromArgb((r - hfdiffi > 0) ? r - hfdiffi : 0,
193 (g - hfdiffi > 0) ? g - hfdiffi : 0,
194 (b - hfdiffi > 0) ? b - hfdiffi : 0);
195
196 mapbmp.SetPixel(x-1, yr+1, color);
197 }
198 }
199 }
200 }
201 }
202 catch (System.ArgumentException)
203 {
204 if (!terraincorruptedwarningsaid)
205 {
206 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
207 terraincorruptedwarningsaid = true;
208 }
209 color = Color.Black;
210 mapbmp.SetPixel(x, yr, color);
211 }
212 }
213 else
214 {
215 // We're under the water level with the terrain, so paint water instead of land
216
217 // Y flip the cordinates
218 heightvalue = waterHeight - heightvalue;
219 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
220 heightvalue = 0f;
221 else if (heightvalue > 19f)
222 heightvalue = 19f;
223 else if (heightvalue < 0f)
224 heightvalue = 0f;
225
226 heightvalue = 100f - (heightvalue * 100f) / 19f;
227
228 try
229 {
230 Color water = Color.FromArgb((int)heightvalue, (int)heightvalue, 255);
231 mapbmp.SetPixel(x, yr, water);
232 }
233 catch (System.ArgumentException)
234 {
235 if (!terraincorruptedwarningsaid)
236 {
237 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
238 terraincorruptedwarningsaid = true;
239 }
240 Color black = Color.Black;
241 mapbmp.SetPixel(x, (256 - y) - 1, black);
242 }
243 }
244 }
245 }
246 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms");
247 }
248 }
249}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs
new file mode 100644
index 0000000..537644a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/TexturedMapTileRenderer.cs
@@ -0,0 +1,411 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Drawing2D;
33using System.Drawing.Imaging;
34using System.Reflection;
35using OpenMetaverse;
36using Nini.Config;
37using log4net;
38using OpenMetaverse.Imaging;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.CoreModules.World.Terrain;
43
44namespace OpenSim.Region.CoreModules.World.WorldMap
45{
46 // Hue, Saturation, Value; used for color-interpolation
47 struct HSV {
48 public float h;
49 public float s;
50 public float v;
51
52 public HSV(float h, float s, float v)
53 {
54 this.h = h;
55 this.s = s;
56 this.v = v;
57 }
58
59 // (for info about algorithm, see http://en.wikipedia.org/wiki/HSL_and_HSV)
60 public HSV(Color c)
61 {
62 float r = c.R / 255f;
63 float g = c.G / 255f;
64 float b = c.B / 255f;
65 float max = Math.Max(Math.Max(r, g), b);
66 float min = Math.Min(Math.Min(r, g), b);
67 float diff = max - min;
68
69 if (max == min) h = 0f;
70 else if (max == r) h = (g - b) / diff * 60f;
71 else if (max == g) h = (b - r) / diff * 60f + 120f;
72 else h = (r - g) / diff * 60f + 240f;
73 if (h < 0f) h += 360f;
74
75 if (max == 0f) s = 0f;
76 else s = diff / max;
77
78 v = max;
79 }
80
81 // (for info about algorithm, see http://en.wikipedia.org/wiki/HSL_and_HSV)
82 public Color toColor()
83 {
84 if (s < 0f) Console.WriteLine("S < 0: " + s);
85 else if (s > 1f) Console.WriteLine("S > 1: " + s);
86 if (v < 0f) Console.WriteLine("V < 0: " + v);
87 else if (v > 1f) Console.WriteLine("V > 1: " + v);
88
89 float f = h / 60f;
90 int sector = (int)f % 6;
91 f = f - (int)f;
92 int pi = (int)(v * (1f - s) * 255f);
93 int qi = (int)(v * (1f - s * f) * 255f);
94 int ti = (int)(v * (1f - (1f - f) * s) * 255f);
95 int vi = (int)(v * 255f);
96
97 switch (sector)
98 {
99 case 0:
100 return Color.FromArgb(vi, ti, pi);
101 case 1:
102 return Color.FromArgb(qi, vi, pi);
103 case 2:
104 return Color.FromArgb(pi, vi, ti);
105 case 3:
106 return Color.FromArgb(pi, qi, vi);
107 case 4:
108 return Color.FromArgb(ti, pi, vi);
109 default:
110 return Color.FromArgb(vi, pi, qi);
111 }
112 }
113 }
114
115 public class TexturedMapTileRenderer : IMapTileTerrainRenderer
116 {
117 #region Constants
118
119 private static readonly ILog m_log =
120 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
121
122 // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank").
123 // The color-values were choosen because they "look right" (at least to me) ;-)
124 private static readonly UUID defaultTerrainTexture1 = new UUID("0bc58228-74a0-7e83-89bc-5c23464bcec5");
125 private static readonly Color defaultColor1 = Color.FromArgb(165, 137, 118);
126 private static readonly UUID defaultTerrainTexture2 = new UUID("63338ede-0037-c4fd-855b-015d77112fc8");
127 private static readonly Color defaultColor2 = Color.FromArgb(69, 89, 49);
128 private static readonly UUID defaultTerrainTexture3 = new UUID("303cd381-8560-7579-23f1-f0a880799740");
129 private static readonly Color defaultColor3 = Color.FromArgb(162, 154, 141);
130 private static readonly UUID defaultTerrainTexture4 = new UUID("53a2f406-4895-1d13-d541-d2e3b86bc19c");
131 private static readonly Color defaultColor4 = Color.FromArgb(200, 200, 200);
132
133 #endregion
134
135
136 private Scene m_scene;
137 // private IConfigSource m_config; // not used currently
138
139 // mapping from texture UUIDs to averaged color. This will contain 5-9 values, in general; new values are only
140 // added when the terrain textures are changed in the estate dialog and a new map is generated (and will stay in
141 // that map until the region-server restarts. This could be considered a memory-leak, but it's a *very* small one.
142 // TODO does it make sense to use a "real" cache and regenerate missing entries on fetch?
143 private Dictionary<UUID, Color> m_mapping;
144
145
146 public void Initialise(Scene scene, IConfigSource source)
147 {
148 m_scene = scene;
149 // m_config = source; // not used currently
150 m_mapping = new Dictionary<UUID,Color>();
151 m_mapping.Add(defaultTerrainTexture1, defaultColor1);
152 m_mapping.Add(defaultTerrainTexture2, defaultColor2);
153 m_mapping.Add(defaultTerrainTexture3, defaultColor3);
154 m_mapping.Add(defaultTerrainTexture4, defaultColor4);
155 m_mapping.Add(Util.BLANK_TEXTURE_UUID, Color.White);
156 }
157
158 #region Helpers
159 // This fetches the texture from the asset server synchroneously. That should be ok, as we
160 // call map-creation only in those places:
161 // - on start: We can wait here until the asset server returns the texture
162 // TODO (- on "map" command: We are in the command-line thread, we will wait for completion anyway)
163 // TODO (- on "automatic" update after some change: We are called from the mapUpdateTimer here and
164 // will wait anyway)
165 private Bitmap fetchTexture(UUID id)
166 {
167 AssetBase asset = m_scene.AssetCache.GetAsset(id, true);
168 m_log.DebugFormat("Fetched texture {0}, found: {1}", id, asset != null);
169 if (asset == null) return null;
170
171 ManagedImage managedImage;
172 Image image;
173
174 try
175 {
176 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
177 return new Bitmap(image);
178 else
179 return null;
180 }
181 catch (DllNotFoundException)
182 {
183 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is emtpy for {0}", id);
184
185 }
186 catch (IndexOutOfRangeException)
187 {
188 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is emtpy for {0}", id);
189
190 }
191 catch (Exception)
192 {
193 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is emtpy for {0}", id);
194
195 }
196 return null;
197
198 }
199
200 // Compute the average color of a texture.
201 private Color computeAverageColor(Bitmap bmp)
202 {
203 // we have 256 x 256 pixel, each with 256 possible color-values per
204 // color-channel, so 2^24 is the maximum value we can get, adding everything.
205 // int is be big enough for that.
206 int r = 0, g = 0, b = 0;
207 for (int y = 0; y < bmp.Height; ++y)
208 {
209 for (int x = 0; x < bmp.Width; ++x)
210 {
211 Color c = bmp.GetPixel(x, y);
212 r += (int)c.R & 0xff;
213 g += (int)c.G & 0xff;
214 b += (int)c.B & 0xff;
215 }
216 }
217
218 int pixels = bmp.Width * bmp.Height;
219 return Color.FromArgb(r / pixels, g / pixels, b / pixels);
220 }
221
222 // return either the average color of the texture, or the defaultColor if the texturID is invalid
223 // or the texture couldn't be found
224 private Color computeAverageColor(UUID textureID, Color defaultColor) {
225 if (textureID == UUID.Zero) return defaultColor; // not set
226 if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures
227
228 Bitmap bmp = fetchTexture(textureID);
229 Color color = bmp == null ? defaultColor : computeAverageColor(bmp);
230 // store it for future reference
231 m_mapping[textureID] = color;
232
233 return color;
234 }
235
236 // S-curve: f(x) = 3x² - 2x³:
237 // f(0) = 0, f(0.5) = 0.5, f(1) = 1,
238 // f'(x) = 0 at x = 0 and x = 1; f'(0.5) = 1.5,
239 // f''(0.5) = 0, f''(x) != 0 for x != 0.5
240 private float S(float v) {
241 return (v * v * (3f - 2f * v));
242 }
243
244 // interpolate two colors in HSV space and return the resulting color
245 private HSV interpolateHSV(ref HSV c1, ref HSV c2, float ratio) {
246 if (ratio <= 0f) return c1;
247 if (ratio >= 1f) return c2;
248
249 // make sure we are on the same side on the hue-circle for interpolation
250 // We change the hue of the parameters here, but we don't change the color
251 // represented by that value
252 if (c1.h - c2.h > 180f) c1.h -= 360f;
253 else if (c2.h - c1.h > 180f) c1.h += 360f;
254
255 return new HSV(c1.h * (1f - ratio) + c2.h * ratio,
256 c1.s * (1f - ratio) + c2.s * ratio,
257 c1.v * (1f - ratio) + c2.v * ratio);
258 }
259
260 // the heigthfield might have some jumps in values. Rendered land is smooth, though,
261 // as a slope is rendered at that place. So average 4 neighbour values to emulate that.
262 private float getHeight(double[,] hm, int x, int y) {
263 if (x < 255 && y < 255)
264 return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112);
265 else
266 return (float)hm[x, y];
267 }
268 #endregion
269
270 public void TerrainToBitmap(Bitmap mapbmp)
271 {
272 int tc = System.Environment.TickCount;
273 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");
274
275 // These textures should be in the AssetCache anyway, as every client conneting to this
276 // region needs them. Except on start, when the map is recreated (before anyone connected),
277 // and on change of the estate settings (textures and terrain values), when the map should
278 // be recreated.
279 RegionSettings settings = m_scene.RegionInfo.RegionSettings;
280
281 // the four terrain colors as HSVs for interpolation
282 HSV hsv1 = new HSV(computeAverageColor(settings.TerrainTexture1, defaultColor1));
283 HSV hsv2 = new HSV(computeAverageColor(settings.TerrainTexture2, defaultColor2));
284 HSV hsv3 = new HSV(computeAverageColor(settings.TerrainTexture3, defaultColor3));
285 HSV hsv4 = new HSV(computeAverageColor(settings.TerrainTexture4, defaultColor4));
286
287 float levelNElow = (float)settings.Elevation1NE;
288 float levelNEhigh = (float)settings.Elevation2NE;
289
290 float levelNWlow = (float)settings.Elevation1NW;
291 float levelNWhigh = (float)settings.Elevation2NW;
292
293 float levelSElow = (float)settings.Elevation1SE;
294 float levelSEhigh = (float)settings.Elevation2SE;
295
296 float levelSWlow = (float)settings.Elevation1SW;
297 float levelSWhigh = (float)settings.Elevation2SW;
298
299 float waterHeight = (float)settings.WaterHeight;
300
301 double[,] hm = m_scene.Heightmap.GetDoubles();
302
303 for (int x = 0; x < 256; x++)
304 {
305 float columnRatio = x / 255f; // 0 - 1, for interpolation
306 for (int y = 0; y < 256; y++)
307 {
308 float rowRatio = y / 255f; // 0 - 1, for interpolation
309
310 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
311 int yr = 255 - y;
312
313 float heightvalue = getHeight(hm, x, y);
314 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
315 heightvalue = 0;
316
317 if (heightvalue > waterHeight)
318 {
319 // add a bit noise for breaking up those flat colors:
320 // - a large-scale noise, for the "patches" (using an doubled s-curve for sharper contrast)
321 // - a small-scale noise, for bringing in some small scale variation
322 //float bigNoise = (float)TerrainUtil.InterpolatedNoise(x / 8.0, y / 8.0) * .5f + .5f; // map to 0.0 - 1.0
323 //float smallNoise = (float)TerrainUtil.InterpolatedNoise(x + 33, y + 43) * .5f + .5f;
324 //float hmod = heightvalue + smallNoise * 3f + S(S(bigNoise)) * 10f;
325 float hmod =
326 heightvalue +
327 (float)TerrainUtil.InterpolatedNoise(x + 33, y + 43) * 1.5f + 1.5f + // 0 - 3
328 S(S((float)TerrainUtil.InterpolatedNoise(x / 8.0, y / 8.0) * .5f + .5f)) * 10f; // 0 - 10
329
330 // find the low/high values for this point (interpolated bilinearily)
331 // (and remember, x=0,y=0 is SW)
332 float low = levelSWlow * (1f - rowRatio) * (1f - columnRatio) +
333 levelSElow * (1f - rowRatio) * columnRatio +
334 levelNWlow * rowRatio * (1f - columnRatio) +
335 levelNElow * rowRatio * columnRatio;
336 float high = levelSWhigh * (1f - rowRatio) * (1f - columnRatio) +
337 levelSEhigh * (1f - rowRatio) * columnRatio +
338 levelNWhigh * rowRatio * (1f - columnRatio) +
339 levelNEhigh * rowRatio * columnRatio;
340 if (high < low)
341 {
342 // someone tried to fool us. High value should be higher than low every time
343 float tmp = high;
344 high = low;
345 low = tmp;
346 }
347
348 HSV hsv;
349 if (hmod <= low) hsv = hsv1; // too low
350 else if (hmod >= high) hsv = hsv4; // too high
351 else
352 {
353 // HSV-interpolate along the colors
354 // first, rescale h to 0.0 - 1.0
355 hmod = (hmod - low) / (high - low);
356 // now we have to split: 0.00 => color1, 0.33 => color2, 0.67 => color3, 1.00 => color4
357 if (hmod < 1f/3f) hsv = interpolateHSV(ref hsv1, ref hsv2, hmod * 3f);
358 else if (hmod < 2f/3f) hsv = interpolateHSV(ref hsv2, ref hsv3, (hmod * 3f) - 1f);
359 else hsv = interpolateHSV(ref hsv3, ref hsv4, (hmod * 3f) - 2f);
360 }
361
362 // Shade the terrain for shadows
363 if (x < 255 && y < 255)
364 {
365 float hfvaluecompare = getHeight(hm, x + 1, y + 1); // light from north-east => look at land height there
366 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
367 hfvaluecompare = 0f;
368
369 float hfdiff = heightvalue - hfvaluecompare; // => positive if NE is lower, negative if here is lower
370 hfdiff *= 0.06f; // some random factor so "it looks good"
371 if (hfdiff > 0.02f)
372 {
373 float highlightfactor = 0.18f;
374 // NE is lower than here
375 // We have to desaturate and lighten the land at the same time
376 hsv.s = (hsv.s - (hfdiff * highlightfactor) > 0f) ? hsv.s - (hfdiff * highlightfactor) : 0f;
377 hsv.v = (hsv.v + (hfdiff * highlightfactor) < 1f) ? hsv.v + (hfdiff * highlightfactor) : 1f;
378 }
379 else if (hfdiff < -0.02f)
380 {
381 // here is lower than NE:
382 // We have to desaturate and blacken the land at the same time
383 hsv.s = (hsv.s + hfdiff > 0f) ? hsv.s + hfdiff : 0f;
384 hsv.v = (hsv.v + hfdiff > 0f) ? hsv.v + hfdiff : 0f;
385 }
386 }
387 mapbmp.SetPixel(x, yr, hsv.toColor());
388 }
389 else
390 {
391 // We're under the water level with the terrain, so paint water instead of land
392
393 heightvalue = waterHeight - heightvalue;
394 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
395 heightvalue = 0f;
396 else if (heightvalue > 19f)
397 heightvalue = 19f;
398 else if (heightvalue < 0f)
399 heightvalue = 0f;
400
401 heightvalue = 100f - (heightvalue * 100f) / 19f; // 0 - 19 => 100 - 0
402
403 Color water = Color.FromArgb((int)heightvalue, (int)heightvalue, 255);
404 mapbmp.SetPixel(x, yr, water);
405 }
406 }
407 }
408 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms");
409 }
410 }
411}
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
new file mode 100644
index 0000000..376e365
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -0,0 +1,905 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.IO;
34using System.Net;
35using System.Reflection;
36using System.Threading;
37using OpenMetaverse;
38using OpenMetaverse.Imaging;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using OpenSim.Framework;
43using OpenSim.Framework.Communications.Cache;
44using OpenSim.Framework.Communications.Capabilities;
45using OpenSim.Framework.Servers;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Framework.Scenes.Types;
49using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
50
51using OSD = OpenMetaverse.StructuredData.OSD;
52using OSDMap = OpenMetaverse.StructuredData.OSDMap;
53using OSDArray = OpenMetaverse.StructuredData.OSDArray;
54
55namespace OpenSim.Region.CoreModules.World.WorldMap
56{
57 public class WorldMapModule : IRegionModule
58 {
59 private static readonly ILog m_log =
60 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
62 private static readonly string m_mapLayerPath = "0001/";
63
64 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
65
66 //private IConfig m_config;
67 protected Scene m_scene;
68 private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
69 private int cachedTime = 0;
70 private byte[] myMapImageJPEG;
71 protected bool m_Enabled = false;
72 private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>();
73 private Dictionary<string, int> m_blacklistedurls = new Dictionary<string, int>();
74 private Dictionary<ulong, int> m_blacklistedregions = new Dictionary<ulong, int>();
75 private Dictionary<ulong, string> m_cachedRegionMapItemsAddress = new Dictionary<ulong, string>();
76 private List<UUID> m_rootAgents = new List<UUID>();
77 private Thread mapItemReqThread;
78 private volatile bool threadrunning = false;
79
80 //private int CacheRegionsDistance = 256;
81
82 #region IRegionModule Members
83
84 public virtual void Initialise(Scene scene, IConfigSource config)
85 {
86 IConfig startupConfig = config.Configs["Startup"];
87 if (startupConfig.GetString("WorldMapModule", "WorldMap") ==
88 "WorldMap")
89 m_Enabled = true;
90
91 if (!m_Enabled)
92 return;
93
94 m_scene = scene;
95 }
96
97 public virtual void PostInitialise()
98 {
99 if (m_Enabled)
100 AddHandlers();
101 }
102
103 public virtual void Close()
104 {
105 }
106
107 public virtual string Name
108 {
109 get { return "WorldMapModule"; }
110 }
111
112 public bool IsSharedModule
113 {
114 get { return false; }
115 }
116
117 #endregion
118
119 protected virtual void AddHandlers()
120 {
121 myMapImageJPEG = new byte[0];
122
123 string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString();
124 regionimage = regionimage.Replace("-", "");
125 m_log.Info("[WORLD MAP]: JPEG Map location: http://" + m_scene.RegionInfo.ExternalEndPoint.Address.ToString() + ":" + m_scene.RegionInfo.HttpPort.ToString() + "/index.php?method=" + regionimage);
126
127 m_scene.CommsManager.HttpServer.AddHTTPHandler(regionimage, OnHTTPGetMapImage);
128 m_scene.CommsManager.HttpServer.AddLLSDHandler(
129 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
130
131 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
132 m_scene.EventManager.OnNewClient += OnNewClient;
133 m_scene.EventManager.OnClientClosed += ClientLoggedOut;
134 m_scene.EventManager.OnMakeChildAgent += MakeChildAgent;
135 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
136 }
137
138 public void OnRegisterCaps(UUID agentID, Caps caps)
139 {
140 //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
141 string capsBase = "/CAPS/" + caps.CapsObjectPath;
142 caps.RegisterHandler("MapLayer",
143 new RestStreamHandler("POST", capsBase + m_mapLayerPath,
144 delegate(string request, string path, string param,
145 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
146 {
147 return MapLayerRequest(request, path, param,
148 agentID, caps);
149 }));
150 }
151
152 /// <summary>
153 /// Callback for a map layer request
154 /// </summary>
155 /// <param name="request"></param>
156 /// <param name="path"></param>
157 /// <param name="param"></param>
158 /// <param name="agentID"></param>
159 /// <param name="caps"></param>
160 /// <returns></returns>
161 public string MapLayerRequest(string request, string path, string param,
162 UUID agentID, Caps caps)
163 {
164 //try
165 //{
166 //m_log.DebugFormat("[MAPLAYER]: request: {0}, path: {1}, param: {2}, agent:{3}",
167 //request, path, param,agentID.ToString());
168
169 // this is here because CAPS map requests work even beyond the 10,000 limit.
170 ScenePresence avatarPresence = null;
171
172 m_scene.TryGetAvatar(agentID, out avatarPresence);
173
174 if (avatarPresence != null)
175 {
176 bool lookup = false;
177
178 lock (cachedMapBlocks)
179 {
180 if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch()))
181 {
182 List<MapBlockData> mapBlocks;
183
184 mapBlocks = cachedMapBlocks;
185 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
186 }
187 else
188 {
189 lookup = true;
190 }
191 }
192 if (lookup)
193 {
194 List<MapBlockData> mapBlocks;
195
196 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks((int)m_scene.RegionInfo.RegionLocX - 8, (int)m_scene.RegionInfo.RegionLocY - 8, (int)m_scene.RegionInfo.RegionLocX + 8, (int)m_scene.RegionInfo.RegionLocY + 8);
197 avatarPresence.ControllingClient.SendMapBlock(mapBlocks,0);
198
199 lock (cachedMapBlocks)
200 cachedMapBlocks = mapBlocks;
201
202 cachedTime = Util.UnixTimeSinceEpoch();
203 }
204 }
205 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
206 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
207 return mapResponse.ToString();
208 }
209
210 /// <summary>
211 ///
212 /// </summary>
213 /// <param name="mapReq"></param>
214 /// <returns></returns>
215 public LLSDMapLayerResponse GetMapLayer(LLSDMapRequest mapReq)
216 {
217 m_log.Debug("[WORLD MAP]: MapLayer Request in region: " + m_scene.RegionInfo.RegionName);
218 LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
219 mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
220 return mapResponse;
221 }
222
223 /// <summary>
224 ///
225 /// </summary>
226 /// <returns></returns>
227 protected static OSDMapLayer GetOSDMapLayerResponse()
228 {
229 OSDMapLayer mapLayer = new OSDMapLayer();
230 mapLayer.Right = 5000;
231 mapLayer.Top = 5000;
232 mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
233
234 return mapLayer;
235 }
236 #region EventHandlers
237
238 /// <summary>
239 /// Registered for event
240 /// </summary>
241 /// <param name="client"></param>
242 private void OnNewClient(IClientAPI client)
243 {
244 client.OnRequestMapBlocks += RequestMapBlocks;
245 client.OnMapItemRequest += HandleMapItemRequest;
246 }
247
248 /// <summary>
249 /// Client logged out, check to see if there are any more root agents in the simulator
250 /// If not, stop the mapItemRequest Thread
251 /// Event handler
252 /// </summary>
253 /// <param name="AgentId">AgentID that logged out</param>
254 private void ClientLoggedOut(UUID AgentId)
255 {
256 List<ScenePresence> presences = m_scene.GetAvatars();
257 int rootcount = 0;
258 for (int i=0;i<presences.Count;i++)
259 {
260 if (presences[i] != null)
261 {
262 if (!presences[i].IsChildAgent)
263 rootcount++;
264 }
265 }
266 if (rootcount <= 1)
267 StopThread();
268
269 lock (m_rootAgents)
270 {
271 if (m_rootAgents.Contains(AgentId))
272 {
273 m_rootAgents.Remove(AgentId);
274 }
275 }
276 }
277 #endregion
278
279 /// <summary>
280 /// Starts the MapItemRequest Thread
281 /// Note that this only gets started when there are actually agents in the region
282 /// Additionally, it gets stopped when there are none.
283 /// </summary>
284 /// <param name="o"></param>
285 private void StartThread(object o)
286 {
287 if (threadrunning) return;
288 threadrunning = true;
289 m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread");
290 mapItemReqThread = new Thread(new ThreadStart(process));
291 mapItemReqThread.IsBackground = true;
292 mapItemReqThread.Name = "MapItemRequestThread";
293 mapItemReqThread.Priority = ThreadPriority.BelowNormal;
294 mapItemReqThread.SetApartmentState(ApartmentState.MTA);
295 mapItemReqThread.Start();
296 ThreadTracker.Add(mapItemReqThread);
297 }
298
299 /// <summary>
300 /// Enqueues a 'stop thread' MapRequestState. Causes the MapItemRequest thread to end
301 /// </summary>
302 private void StopThread()
303 {
304 MapRequestState st = new MapRequestState();
305 st.agentID=UUID.Zero;
306 st.EstateID=0;
307 st.flags=0;
308 st.godlike=false;
309 st.itemtype=0;
310 st.regionhandle=0;
311
312 requests.Enqueue(st);
313 }
314
315 public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
316 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
317 {
318 lock (m_rootAgents)
319 {
320 if (!m_rootAgents.Contains(remoteClient.AgentId))
321 return;
322 }
323 uint xstart = 0;
324 uint ystart = 0;
325 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
326 if (itemtype == 6) // we only sevice 6 right now (avatar green dots)
327 {
328 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
329 {
330 // Local Map Item Request
331 List<ScenePresence> avatars = m_scene.GetAvatars();
332 int tc = System.Environment.TickCount;
333 List<mapItemReply> mapitems = new List<mapItemReply>();
334 mapItemReply mapitem = new mapItemReply();
335 if (avatars.Count == 0 || avatars.Count == 1)
336 {
337 mapitem = new mapItemReply();
338 mapitem.x = (uint)(xstart + 1);
339 mapitem.y = (uint)(ystart + 1);
340 mapitem.id = UUID.Zero;
341 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
342 mapitem.Extra = 0;
343 mapitem.Extra2 = 0;
344 mapitems.Add(mapitem);
345 }
346 else
347 {
348 foreach (ScenePresence av in avatars)
349 {
350 // Don't send a green dot for yourself
351 if (av.UUID != remoteClient.AgentId)
352 {
353 mapitem = new mapItemReply();
354 mapitem.x = (uint)(xstart + av.AbsolutePosition.X);
355 mapitem.y = (uint)(ystart + av.AbsolutePosition.Y);
356 mapitem.id = UUID.Zero;
357 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
358 mapitem.Extra = 1;
359 mapitem.Extra2 = 0;
360 mapitems.Add(mapitem);
361 }
362 }
363 }
364 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
365 }
366 else
367 {
368 // Remote Map Item Request
369
370 // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes.
371 // Note that we only start up a remote mapItem Request thread if there's users who could
372 // be making requests
373 if (!threadrunning)
374 {
375 m_log.Warn("[WORLD MAP]: Starting new remote request thread manually. This means that AvatarEnteringParcel never fired! This needs to be fixed! Don't Mantis this, as the developers can see it in this message");
376 StartThread(new object());
377 }
378
379 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
380 }
381 }
382 }
383
384 /// <summary>
385 /// Processing thread main() loop for doing remote mapitem requests
386 /// </summary>
387 public void process()
388 {
389 try
390 {
391 while (true)
392 {
393 MapRequestState st = requests.Dequeue();
394
395 // end gracefully
396 if (st.agentID == UUID.Zero)
397 {
398 ThreadTracker.Remove(mapItemReqThread);
399 break;
400 }
401
402 bool dorequest = true;
403 lock (m_rootAgents)
404 {
405 if (!m_rootAgents.Contains(st.agentID))
406 dorequest = false;
407 }
408
409 if (dorequest)
410 {
411 OSDMap response = RequestMapItemsAsync("", st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
412 RequestMapItemsCompleted(response);
413 }
414 }
415 }
416 catch (Exception e)
417 {
418 m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e);
419 }
420
421 threadrunning = false;
422 }
423
424 /// <summary>
425 /// Enqueues the map item request into the processing thread
426 /// </summary>
427 /// <param name="state"></param>
428 public void EnqueueMapItemRequest(MapRequestState state)
429 {
430 requests.Enqueue(state);
431 }
432
433 /// <summary>
434 /// Sends the mapitem response to the IClientAPI
435 /// </summary>
436 /// <param name="response">The OSDMap Response for the mapitem</param>
437 private void RequestMapItemsCompleted(OSDMap response)
438 {
439 UUID requestID = response["requestID"].AsUUID();
440
441 if (requestID != UUID.Zero)
442 {
443 MapRequestState mrs = new MapRequestState();
444 mrs.agentID = UUID.Zero;
445 lock (m_openRequests)
446 {
447 if (m_openRequests.ContainsKey(requestID))
448 {
449 mrs = m_openRequests[requestID];
450 m_openRequests.Remove(requestID);
451 }
452 }
453
454 if (mrs.agentID != UUID.Zero)
455 {
456 ScenePresence av = null;
457 m_scene.TryGetAvatar(mrs.agentID, out av);
458 if (av != null)
459 {
460 if (response.ContainsKey(mrs.itemtype.ToString()))
461 {
462 List<mapItemReply> returnitems = new List<mapItemReply>();
463 OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()];
464 for (int i = 0; i < itemarray.Count; i++)
465 {
466 OSDMap mapitem = (OSDMap)itemarray[i];
467 mapItemReply mi = new mapItemReply();
468 mi.x = (uint)mapitem["X"].AsInteger();
469 mi.y = (uint)mapitem["Y"].AsInteger();
470 mi.id = mapitem["ID"].AsUUID();
471 mi.Extra = mapitem["Extra"].AsInteger();
472 mi.Extra2 = mapitem["Extra2"].AsInteger();
473 mi.name = mapitem["Name"].AsString();
474 returnitems.Add(mi);
475 }
476 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
477 }
478 }
479 }
480 }
481 }
482
483 /// <summary>
484 /// Enqueue the MapItem request for remote processing
485 /// </summary>
486 /// <param name="httpserver">blank string, we discover this in the process</param>
487 /// <param name="id">Agent ID that we are making this request on behalf</param>
488 /// <param name="flags">passed in from packet</param>
489 /// <param name="EstateID">passed in from packet</param>
490 /// <param name="godlike">passed in from packet</param>
491 /// <param name="itemtype">passed in from packet</param>
492 /// <param name="regionhandle">Region we're looking up</param>
493 public void RequestMapItems(string httpserver, UUID id, uint flags,
494 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
495 {
496 MapRequestState st = new MapRequestState();
497 st.agentID = id;
498 st.flags = flags;
499 st.EstateID = EstateID;
500 st.godlike = godlike;
501 st.itemtype = itemtype;
502 st.regionhandle = regionhandle;
503 EnqueueMapItemRequest(st);
504 }
505
506 /// <summary>
507 /// Does the actual remote mapitem request
508 /// This should be called from an asynchronous thread
509 /// Request failures get blacklisted until region restart so we don't
510 /// continue to spend resources trying to contact regions that are down.
511 /// </summary>
512 /// <param name="httpserver">blank string, we discover this in the process</param>
513 /// <param name="id">Agent ID that we are making this request on behalf</param>
514 /// <param name="flags">passed in from packet</param>
515 /// <param name="EstateID">passed in from packet</param>
516 /// <param name="godlike">passed in from packet</param>
517 /// <param name="itemtype">passed in from packet</param>
518 /// <param name="regionhandle">Region we're looking up</param>
519 /// <returns></returns>
520 private OSDMap RequestMapItemsAsync(string httpserver, UUID id, uint flags,
521 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
522 {
523 bool blacklisted = false;
524 lock (m_blacklistedregions)
525 {
526 if (m_blacklistedregions.ContainsKey(regionhandle))
527 blacklisted = true;
528 }
529
530 if (blacklisted)
531 return new OSDMap();
532
533 UUID requestID = UUID.Random();
534 lock (m_cachedRegionMapItemsAddress)
535 {
536 if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
537 httpserver = m_cachedRegionMapItemsAddress[regionhandle];
538 }
539 if (httpserver.Length == 0)
540 {
541 RegionInfo mreg = m_scene.SceneGridService.RequestNeighbouringRegionInfo(regionhandle);
542
543 if (mreg != null)
544 {
545 httpserver = "http://" + mreg.ExternalEndPoint.Address.ToString() + ":" + mreg.HttpPort + "/MAP/MapItems/" + regionhandle.ToString();
546 lock (m_cachedRegionMapItemsAddress)
547 {
548 if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
549 m_cachedRegionMapItemsAddress.Add(regionhandle, httpserver);
550 }
551 }
552 else
553 {
554 lock (m_blacklistedregions)
555 {
556 if (!m_blacklistedregions.ContainsKey(regionhandle))
557 m_blacklistedregions.Add(regionhandle, System.Environment.TickCount);
558 }
559 m_log.InfoFormat("[WORLD MAP]: Blacklisted region {0}", regionhandle.ToString());
560 }
561 }
562
563 blacklisted = false;
564 lock (m_blacklistedurls)
565 {
566 if (m_blacklistedurls.ContainsKey(httpserver))
567 blacklisted = true;
568 }
569
570 // Can't find the http server
571 if (httpserver.Length == 0 || blacklisted)
572 return new OSDMap();
573
574 MapRequestState mrs = new MapRequestState();
575 mrs.agentID = id;
576 mrs.EstateID = EstateID;
577 mrs.flags = flags;
578 mrs.godlike = godlike;
579 mrs.itemtype=itemtype;
580 mrs.regionhandle = regionhandle;
581
582 lock (m_openRequests)
583 m_openRequests.Add(requestID, mrs);
584
585 WebRequest mapitemsrequest = WebRequest.Create(httpserver);
586 mapitemsrequest.Method = "POST";
587 mapitemsrequest.ContentType = "application/xml+llsd";
588 OSDMap RAMap = new OSDMap();
589
590 // string RAMapString = RAMap.ToString();
591 OSD LLSDofRAMap = RAMap; // RENAME if this works
592
593 byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap);
594 OSDMap responseMap = new OSDMap();
595 responseMap["requestID"] = OSD.FromUUID(requestID);
596
597 Stream os = null;
598 try
599 { // send the Post
600 mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send
601 os = mapitemsrequest.GetRequestStream();
602 os.Write(buffer, 0, buffer.Length); //Send it
603 os.Close();
604 //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from Sim {0}", httpserver);
605 }
606 catch (WebException ex)
607 {
608 m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message);
609 responseMap["connect"] = OSD.FromBoolean(false);
610 lock (m_blacklistedurls)
611 {
612 if (!m_blacklistedurls.ContainsKey(httpserver))
613 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
614 }
615
616 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
617
618 return responseMap;
619 }
620
621 string response_mapItems_reply = null;
622 { // get the response
623 try
624 {
625 WebResponse webResponse = mapitemsrequest.GetResponse();
626 if (webResponse != null)
627 {
628 StreamReader sr = new StreamReader(webResponse.GetResponseStream());
629 response_mapItems_reply = sr.ReadToEnd().Trim();
630 }
631 else
632 {
633 return new OSDMap();
634 }
635 }
636 catch (WebException)
637 {
638 responseMap["connect"] = OSD.FromBoolean(false);
639 lock (m_blacklistedurls)
640 {
641 if (!m_blacklistedurls.ContainsKey(httpserver))
642 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
643 }
644
645 m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver);
646
647 return responseMap;
648 }
649 OSD rezResponse = null;
650 try
651 {
652 rezResponse = OSDParser.DeserializeLLSDXml(response_mapItems_reply);
653
654 responseMap = (OSDMap)rezResponse;
655 responseMap["requestID"] = OSD.FromUUID(requestID);
656 }
657 catch (Exception)
658 {
659 //m_log.InfoFormat("[OGP]: exception on parse of rez reply {0}", ex.Message);
660 responseMap["connect"] = OSD.FromBoolean(false);
661
662 return responseMap;
663 }
664 }
665 return responseMap;
666 }
667
668 /// <summary>
669 /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates
670 /// </summary>
671 /// <param name="minX"></param>
672 /// <param name="minY"></param>
673 /// <param name="maxX"></param>
674 /// <param name="maxY"></param>
675 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
676 {
677 List<MapBlockData> mapBlocks;
678 if ((flag & 0x10000) != 0) // user clicked on the map a tile that isn't visible
679 {
680 List<MapBlockData> response = new List<MapBlockData>();
681
682 // this should return one mapblock at most. But make sure: Look whether the one we requested is in there
683 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY);
684 if (mapBlocks != null)
685 {
686 foreach (MapBlockData block in mapBlocks)
687 {
688 if (block.X == minX && block.Y == minY)
689 {
690 // found it => add it to response
691 response.Add(block);
692 break;
693 }
694 }
695 }
696
697 if (response.Count == 0)
698 {
699 // response still empty => couldn't find the map-tile the user clicked on => tell the client
700 MapBlockData block = new MapBlockData();
701 block.X = (ushort)minX;
702 block.Y = (ushort)minY;
703 block.Access = 254; // == not there
704 response.Add(block);
705 }
706 remoteClient.SendMapBlock(response, 0);
707 }
708 else
709 {
710 // normal mapblock request. Use the provided values
711 mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX - 4, minY - 4, maxX + 4, maxY + 4);
712 remoteClient.SendMapBlock(mapBlocks, flag);
713 }
714 }
715
716 public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
717 {
718 m_log.Debug("[WORLD MAP]: Sending map image jpeg");
719 Hashtable reply = new Hashtable();
720 int statuscode = 200;
721 byte[] jpeg = new byte[0];
722
723 if (myMapImageJPEG.Length == 0)
724 {
725 MemoryStream imgstream = new MemoryStream();
726 Bitmap mapTexture = new Bitmap(1,1);
727 ManagedImage managedImage;
728 Image image = (Image)mapTexture;
729
730 try
731 {
732 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data
733
734 imgstream = new MemoryStream();
735
736 // non-async because we know we have the asset immediately.
737 AssetBase mapasset = m_scene.AssetCache.GetAsset(m_scene.RegionInfo.lastMapUUID, true);
738
739 // Decode image to System.Drawing.Image
740 if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image))
741 {
742 // Save to bitmap
743 mapTexture = new Bitmap(image);
744
745 EncoderParameters myEncoderParameters = new EncoderParameters();
746 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L);
747
748 // Save bitmap to stream
749 mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters);
750
751 // Write the stream to a byte array for output
752 jpeg = imgstream.ToArray();
753 myMapImageJPEG = jpeg;
754 }
755 }
756 catch (Exception)
757 {
758 // Dummy!
759 m_log.Warn("[WORLD MAP]: Unable to generate Map image");
760 }
761 finally
762 {
763 // Reclaim memory, these are unmanaged resources
764 mapTexture.Dispose();
765 image.Dispose();
766 imgstream.Close();
767 imgstream.Dispose();
768 }
769 }
770 else
771 {
772 // Use cached version so we don't have to loose our mind
773 jpeg = myMapImageJPEG;
774 }
775
776 reply["str_response_string"] = Convert.ToBase64String(jpeg);
777 reply["int_response_code"] = statuscode;
778 reply["content_type"] = "image/jpeg";
779
780 return reply;
781 }
782
783 // From msdn
784 private static ImageCodecInfo GetEncoderInfo(String mimeType)
785 {
786 ImageCodecInfo[] encoders;
787 encoders = ImageCodecInfo.GetImageEncoders();
788 for (int j = 0; j < encoders.Length; ++j)
789 {
790 if (encoders[j].MimeType == mimeType)
791 return encoders[j];
792 }
793 return null;
794 }
795
796 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
797 {
798 uint xstart = 0;
799 uint ystart = 0;
800
801 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
802
803 OSDMap responsemap = new OSDMap();
804 List<ScenePresence> avatars = m_scene.GetAvatars();
805 OSDArray responsearr = new OSDArray(avatars.Count);
806 OSDMap responsemapdata = new OSDMap();
807 int tc = System.Environment.TickCount;
808 /*
809 foreach (ScenePresence av in avatars)
810 {
811 responsemapdata = new OSDMap();
812 responsemapdata["X"] = OSD.FromInteger((int)(xstart + av.AbsolutePosition.X));
813 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + av.AbsolutePosition.Y));
814 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
815 responsemapdata["Name"] = OSD.FromString("TH");
816 responsemapdata["Extra"] = OSD.FromInteger(0);
817 responsemapdata["Extra2"] = OSD.FromInteger(0);
818 responsearr.Add(responsemapdata);
819 }
820 responsemap["1"] = responsearr;
821 */
822 if (avatars.Count == 0)
823 {
824 responsemapdata = new OSDMap();
825 responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1));
826 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1));
827 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
828 responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
829 responsemapdata["Extra"] = OSD.FromInteger(0);
830 responsemapdata["Extra2"] = OSD.FromInteger(0);
831 responsearr.Add(responsemapdata);
832
833 responsemap["6"] = responsearr;
834 }
835 else
836 {
837 responsearr = new OSDArray(avatars.Count);
838 foreach (ScenePresence av in avatars)
839 {
840 responsemapdata = new OSDMap();
841 responsemapdata["X"] = OSD.FromInteger((int)(xstart + av.AbsolutePosition.X));
842 responsemapdata["Y"] = OSD.FromInteger((int)(ystart + av.AbsolutePosition.Y));
843 responsemapdata["ID"] = OSD.FromUUID(UUID.Zero);
844 responsemapdata["Name"] = OSD.FromString(Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()));
845 responsemapdata["Extra"] = OSD.FromInteger(1);
846 responsemapdata["Extra2"] = OSD.FromInteger(0);
847 responsearr.Add(responsemapdata);
848 }
849 responsemap["6"] = responsearr;
850 }
851 return responsemap;
852 }
853
854 private void MakeRootAgent(ScenePresence avatar)
855 {
856 // You may ask, why this is in a threadpool to start with..
857 // The reason is so we don't cause the thread to freeze waiting
858 // for the 1 second it costs to start a thread manually.
859 if (!threadrunning)
860 ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartThread));
861
862 lock (m_rootAgents)
863 {
864 if (!m_rootAgents.Contains(avatar.UUID))
865 {
866 m_rootAgents.Add(avatar.UUID);
867 }
868 }
869 }
870
871 private void MakeChildAgent(ScenePresence avatar)
872 {
873 List<ScenePresence> presences = m_scene.GetAvatars();
874 int rootcount = 0;
875 for (int i = 0; i < presences.Count; i++)
876 {
877 if (presences[i] != null)
878 {
879 if (!presences[i].IsChildAgent)
880 rootcount++;
881 }
882 }
883 if (rootcount <= 1)
884 StopThread();
885
886 lock (m_rootAgents)
887 {
888 if (m_rootAgents.Contains(avatar.UUID))
889 {
890 m_rootAgents.Remove(avatar.UUID);
891 }
892 }
893 }
894 }
895
896 public struct MapRequestState
897 {
898 public UUID agentID;
899 public uint flags;
900 public uint EstateID;
901 public bool godlike;
902 public uint itemtype;
903 public ulong regionhandle;
904 }
905}