clockwerk-opensim-stable – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ |
||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions are met: |
||
7 | * * Redistributions of source code must retain the above copyright |
||
8 | * notice, this list of conditions and the following disclaimer. |
||
9 | * * Redistributions in binary form must reproduce the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer in the |
||
11 | * documentation and/or other materials provided with the distribution. |
||
12 | * * Neither the name of the OpenSimulator Project nor the |
||
13 | * names of its contributors may be used to endorse or promote products |
||
14 | * derived from this software without specific prior written permission. |
||
15 | * |
||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
26 | */ |
||
27 | |||
28 | using System; |
||
29 | using System.Collections.Generic; |
||
30 | using System.IO; |
||
31 | using System.IO.Compression; |
||
32 | using System.Net; |
||
33 | using System.Reflection; |
||
34 | using System.Text; |
||
35 | using System.Xml; |
||
36 | using log4net; |
||
37 | using OpenMetaverse; |
||
38 | using OpenSim.Framework; |
||
39 | using OpenSim.Framework.Serialization; |
||
40 | using OpenSim.Framework.Serialization.External; |
||
41 | using OpenSim.Region.CoreModules.World.Terrain; |
||
42 | using OpenSim.Region.Framework.Interfaces; |
||
43 | using OpenSim.Region.Framework.Scenes; |
||
44 | using OpenSim.Region.Framework.Scenes.Serialization; |
||
45 | using OpenSim.Services.Interfaces; |
||
46 | using System.Threading; |
||
47 | |||
48 | namespace OpenSim.Region.CoreModules.World.Archiver |
||
49 | { |
||
50 | /// <summary> |
||
51 | /// Handles an individual archive read request |
||
52 | /// </summary> |
||
53 | public class ArchiveReadRequest |
||
54 | { |
||
55 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
56 | |||
57 | /// <summary> |
||
58 | /// Contains data used while dearchiving a single scene. |
||
59 | /// </summary> |
||
60 | private class DearchiveContext |
||
61 | { |
||
62 | public Scene Scene { get; set; } |
||
63 | |||
64 | public List<string> SerialisedSceneObjects { get; set; } |
||
65 | |||
66 | public List<string> SerialisedParcels { get; set; } |
||
67 | |||
68 | public List<SceneObjectGroup> SceneObjects { get; set; } |
||
69 | |||
70 | public DearchiveContext(Scene scene) |
||
71 | { |
||
72 | Scene = scene; |
||
73 | SerialisedSceneObjects = new List<string>(); |
||
74 | SerialisedParcels = new List<string>(); |
||
75 | SceneObjects = new List<SceneObjectGroup>(); |
||
76 | } |
||
77 | } |
||
78 | |||
79 | |||
80 | /// <summary> |
||
81 | /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version |
||
82 | /// bumps here should be compatible. |
||
83 | /// </summary> |
||
84 | public static int MAX_MAJOR_VERSION = 1; |
||
85 | |||
86 | /// <summary> |
||
87 | /// Has the control file been loaded for this archive? |
||
88 | /// </summary> |
||
89 | public bool ControlFileLoaded { get; private set; } |
||
90 | |||
91 | protected string m_loadPath; |
||
92 | protected Scene m_rootScene; |
||
93 | protected Stream m_loadStream; |
||
94 | protected Guid m_requestId; |
||
95 | protected string m_errorMessage; |
||
96 | |||
97 | /// <value> |
||
98 | /// Should the archive being loaded be merged with what is already on the region? |
||
99 | /// </value> |
||
100 | protected bool m_merge; |
||
101 | |||
102 | /// <value> |
||
103 | /// Should we ignore any assets when reloading the archive? |
||
104 | /// </value> |
||
105 | protected bool m_skipAssets; |
||
106 | |||
107 | /// <summary> |
||
108 | /// Used to cache lookups for valid uuids. |
||
109 | /// </summary> |
||
110 | private IDictionary<UUID, bool> m_validUserUuids = new Dictionary<UUID, bool>(); |
||
111 | |||
112 | private IUserManagement m_UserMan; |
||
113 | private IUserManagement UserManager |
||
114 | { |
||
115 | get |
||
116 | { |
||
117 | if (m_UserMan == null) |
||
118 | { |
||
119 | m_UserMan = m_rootScene.RequestModuleInterface<IUserManagement>(); |
||
120 | } |
||
121 | return m_UserMan; |
||
122 | } |
||
123 | } |
||
124 | |||
125 | /// <summary> |
||
126 | /// Used to cache lookups for valid groups. |
||
127 | /// </summary> |
||
128 | private IDictionary<UUID, bool> m_validGroupUuids = new Dictionary<UUID, bool>(); |
||
129 | |||
130 | private IGroupsModule m_groupsModule; |
||
131 | |||
132 | private IAssetService m_assetService = null; |
||
133 | |||
134 | |||
135 | public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) |
||
136 | { |
||
137 | m_rootScene = scene; |
||
138 | |||
139 | m_loadPath = loadPath; |
||
140 | try |
||
141 | { |
||
142 | m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress); |
||
143 | } |
||
144 | catch (EntryPointNotFoundException e) |
||
145 | { |
||
146 | m_log.ErrorFormat( |
||
147 | "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." |
||
148 | + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); |
||
149 | m_log.Error(e); |
||
150 | } |
||
151 | |||
152 | m_errorMessage = String.Empty; |
||
153 | m_merge = merge; |
||
154 | m_skipAssets = skipAssets; |
||
155 | m_requestId = requestId; |
||
156 | |||
157 | // Zero can never be a valid user id |
||
158 | m_validUserUuids[UUID.Zero] = false; |
||
159 | |||
160 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); |
||
161 | m_assetService = m_rootScene.AssetService; |
||
162 | } |
||
163 | |||
164 | public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) |
||
165 | { |
||
166 | m_rootScene = scene; |
||
167 | m_loadPath = null; |
||
168 | m_loadStream = loadStream; |
||
169 | m_merge = merge; |
||
170 | m_skipAssets = skipAssets; |
||
171 | m_requestId = requestId; |
||
172 | |||
173 | // Zero can never be a valid user id |
||
174 | m_validUserUuids[UUID.Zero] = false; |
||
175 | |||
176 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); |
||
177 | m_assetService = m_rootScene.AssetService; |
||
178 | } |
||
179 | |||
180 | /// <summary> |
||
181 | /// Dearchive the region embodied in this request. |
||
182 | /// </summary> |
||
183 | public void DearchiveRegion() |
||
184 | { |
||
185 | int successfulAssetRestores = 0; |
||
186 | int failedAssetRestores = 0; |
||
187 | |||
188 | DearchiveScenesInfo dearchivedScenes; |
||
189 | |||
190 | // We dearchive all the scenes at once, because the files in the TAR archive might be mixed. |
||
191 | // Therefore, we have to keep track of the dearchive context of all the scenes. |
||
192 | Dictionary<UUID, DearchiveContext> sceneContexts = new Dictionary<UUID, DearchiveContext>(); |
||
193 | |||
194 | string fullPath = "NONE"; |
||
195 | TarArchiveReader archive = null; |
||
196 | byte[] data; |
||
197 | TarArchiveReader.TarEntryType entryType; |
||
198 | |||
199 | try |
||
200 | { |
||
201 | FindAndLoadControlFile(out archive, out dearchivedScenes); |
||
202 | |||
203 | while ((data = archive.ReadEntry(out fullPath, out entryType)) != null) |
||
204 | { |
||
205 | //m_log.DebugFormat( |
||
206 | // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length); |
||
207 | |||
208 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) |
||
209 | continue; |
||
210 | |||
211 | |||
212 | // Find the scene that this file belongs to |
||
213 | |||
214 | Scene scene; |
||
215 | string filePath; |
||
216 | if (!dearchivedScenes.GetRegionFromPath(fullPath, out scene, out filePath)) |
||
217 | continue; // this file belongs to a region that we're not loading |
||
218 | |||
219 | DearchiveContext sceneContext = null; |
||
220 | if (scene != null) |
||
221 | { |
||
222 | if (!sceneContexts.TryGetValue(scene.RegionInfo.RegionID, out sceneContext)) |
||
223 | { |
||
224 | sceneContext = new DearchiveContext(scene); |
||
225 | sceneContexts.Add(scene.RegionInfo.RegionID, sceneContext); |
||
226 | } |
||
227 | } |
||
228 | |||
229 | |||
230 | // Process the file |
||
231 | |||
232 | if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) |
||
233 | { |
||
234 | sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); |
||
235 | } |
||
236 | else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets) |
||
237 | { |
||
238 | if (LoadAsset(filePath, data)) |
||
239 | successfulAssetRestores++; |
||
240 | else |
||
241 | failedAssetRestores++; |
||
242 | |||
243 | if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) |
||
244 | m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); |
||
245 | } |
||
246 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) |
||
247 | { |
||
248 | LoadTerrain(scene, filePath, data); |
||
249 | } |
||
250 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) |
||
251 | { |
||
252 | LoadRegionSettings(scene, filePath, data, dearchivedScenes); |
||
253 | } |
||
254 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) |
||
255 | { |
||
256 | sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); |
||
257 | } |
||
258 | else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) |
||
259 | { |
||
260 | // Ignore, because we already read the control file |
||
261 | } |
||
262 | } |
||
263 | |||
264 | //m_log.Debug("[ARCHIVER]: Reached end of archive"); |
||
265 | } |
||
266 | catch (Exception e) |
||
267 | { |
||
268 | m_log.Error( |
||
269 | String.Format("[ARCHIVER]: Aborting load with error in archive file {0} ", fullPath), e); |
||
270 | m_errorMessage += e.ToString(); |
||
271 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage); |
||
272 | return; |
||
273 | } |
||
274 | finally |
||
275 | { |
||
276 | if (archive != null) |
||
277 | archive.Close(); |
||
278 | } |
||
279 | |||
280 | if (!m_skipAssets) |
||
281 | { |
||
282 | m_log.InfoFormat("[ARCHIVER]: Restored {0} assets", successfulAssetRestores); |
||
283 | |||
284 | if (failedAssetRestores > 0) |
||
285 | { |
||
286 | m_log.ErrorFormat("[ARCHIVER]: Failed to load {0} assets", failedAssetRestores); |
||
287 | m_errorMessage += String.Format("Failed to load {0} assets", failedAssetRestores); |
||
288 | } |
||
289 | } |
||
290 | |||
291 | foreach (DearchiveContext sceneContext in sceneContexts.Values) |
||
292 | { |
||
293 | m_log.InfoFormat("[ARCHIVER]: Loading region {0}", sceneContext.Scene.RegionInfo.RegionName); |
||
294 | |||
295 | if (!m_merge) |
||
296 | { |
||
297 | m_log.Info("[ARCHIVER]: Clearing all existing scene objects"); |
||
298 | sceneContext.Scene.DeleteAllSceneObjects(); |
||
299 | } |
||
300 | |||
301 | try |
||
302 | { |
||
303 | LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels); |
||
304 | LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects); |
||
305 | |||
306 | // Inform any interested parties that the region has changed. We waited until now so that all |
||
307 | // of the region's objects will be loaded when we send this notification. |
||
308 | IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface<IEstateModule>(); |
||
309 | if (estateModule != null) |
||
310 | estateModule.TriggerRegionInfoChange(); |
||
311 | } |
||
312 | catch (Exception e) |
||
313 | { |
||
314 | m_log.Error("[ARCHIVER]: Error loading parcels or objects ", e); |
||
315 | m_errorMessage += e.ToString(); |
||
316 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage); |
||
317 | return; |
||
318 | } |
||
319 | } |
||
320 | |||
321 | // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so |
||
322 | // that users can enter the scene. If we allow the scripts to start in the loop above |
||
323 | // then they significantly increase the time until the OAR finishes loading. |
||
324 | Util.FireAndForget(delegate(object o) |
||
325 | { |
||
326 | Thread.Sleep(15000); |
||
327 | m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); |
||
328 | |||
329 | foreach (DearchiveContext sceneContext in sceneContexts.Values) |
||
330 | { |
||
331 | foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects) |
||
332 | { |
||
333 | sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart |
||
334 | sceneObject.ResumeScripts(); |
||
335 | } |
||
336 | |||
337 | sceneContext.SceneObjects.Clear(); |
||
338 | } |
||
339 | }); |
||
340 | |||
341 | m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); |
||
342 | |||
343 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, dearchivedScenes.GetLoadedScenes(), m_errorMessage); |
||
344 | } |
||
345 | |||
346 | /// <summary> |
||
347 | /// Searches through the files in the archive for the control file, and reads it. |
||
348 | /// We must read the control file first, in order to know which regions are available. |
||
349 | /// </summary> |
||
350 | /// <remarks> |
||
351 | /// In most cases the control file *is* first, since that's how we create archives. However, |
||
352 | /// it's possible that someone rewrote the archive externally so we can't rely on this fact. |
||
353 | /// </remarks> |
||
354 | /// <param name="archive"></param> |
||
355 | /// <param name="dearchivedScenes"></param> |
||
356 | private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes) |
||
357 | { |
||
358 | archive = new TarArchiveReader(m_loadStream); |
||
359 | dearchivedScenes = new DearchiveScenesInfo(); |
||
360 | |||
361 | string filePath; |
||
362 | byte[] data; |
||
363 | TarArchiveReader.TarEntryType entryType; |
||
364 | bool firstFile = true; |
||
365 | |||
366 | while ((data = archive.ReadEntry(out filePath, out entryType)) != null) |
||
367 | { |
||
368 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) |
||
369 | continue; |
||
370 | |||
371 | if (filePath == ArchiveConstants.CONTROL_FILE_PATH) |
||
372 | { |
||
373 | LoadControlFile(filePath, data, dearchivedScenes); |
||
374 | |||
375 | // Find which scenes are available in the simulator |
||
376 | ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup(); |
||
377 | SceneManager.Instance.ForEachScene(delegate(Scene scene2) |
||
378 | { |
||
379 | simulatorScenes.AddScene(scene2); |
||
380 | }); |
||
381 | simulatorScenes.CalcSceneLocations(); |
||
382 | dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes); |
||
383 | |||
384 | // If the control file wasn't the first file then reset the read pointer |
||
385 | if (!firstFile) |
||
386 | { |
||
387 | m_log.Warn("Control file wasn't the first file in the archive"); |
||
388 | if (m_loadStream.CanSeek) |
||
389 | { |
||
390 | m_loadStream.Seek(0, SeekOrigin.Begin); |
||
391 | } |
||
392 | else if (m_loadPath != null) |
||
393 | { |
||
394 | archive.Close(); |
||
395 | archive = null; |
||
396 | m_loadStream.Close(); |
||
397 | m_loadStream = null; |
||
398 | m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress); |
||
399 | archive = new TarArchiveReader(m_loadStream); |
||
400 | } |
||
401 | else |
||
402 | { |
||
403 | // There isn't currently a scenario where this happens, but it's best to add a check just in case |
||
404 | throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking"); |
||
405 | } |
||
406 | } |
||
407 | |||
408 | return; |
||
409 | } |
||
410 | |||
411 | firstFile = false; |
||
412 | } |
||
413 | |||
414 | throw new Exception("Control file not found"); |
||
415 | } |
||
416 | |||
417 | /// <summary> |
||
418 | /// Load serialized scene objects. |
||
419 | /// </summary> |
||
420 | protected void LoadObjects(Scene scene, List<string> serialisedSceneObjects, List<SceneObjectGroup> sceneObjects) |
||
421 | { |
||
422 | // Reload serialized prims |
||
423 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); |
||
424 | |||
425 | UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; |
||
426 | |||
427 | IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); |
||
428 | int sceneObjectsLoadedCount = 0; |
||
429 | |||
430 | foreach (string serialisedSceneObject in serialisedSceneObjects) |
||
431 | { |
||
432 | /* |
||
433 | m_log.DebugFormat("[ARCHIVER]: Loading xml with raw size {0}", serialisedSceneObject.Length); |
||
434 | |||
435 | // Really large xml files (multi megabyte) appear to cause |
||
436 | // memory problems |
||
437 | // when loading the xml. But don't enable this check yet |
||
438 | |||
439 | if (serialisedSceneObject.Length > 5000000) |
||
440 | { |
||
441 | m_log.Error("[ARCHIVER]: Ignoring xml since size > 5000000);"); |
||
442 | continue; |
||
443 | } |
||
444 | */ |
||
445 | |||
446 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); |
||
447 | |||
448 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); |
||
449 | |||
450 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned |
||
451 | // on the same region server and multiple examples a single object archive to be imported |
||
452 | // to the same scene (when this is possible). |
||
453 | sceneObject.ResetIDs(); |
||
454 | |||
455 | if (isTelehub) |
||
456 | { |
||
457 | // Change the Telehub Object to the new UUID |
||
458 | scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID; |
||
459 | scene.RegionInfo.RegionSettings.Save(); |
||
460 | oldTelehubUUID = UUID.Zero; |
||
461 | } |
||
462 | |||
463 | // Try to retain the original creator/owner/lastowner if their uuid is present on this grid |
||
464 | // or creator data is present. Otherwise, use the estate owner instead. |
||
465 | foreach (SceneObjectPart part in sceneObject.Parts) |
||
466 | { |
||
467 | if (part.CreatorData == null || part.CreatorData == string.Empty) |
||
468 | { |
||
469 | if (!ResolveUserUuid(scene, part.CreatorID)) |
||
470 | part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
471 | } |
||
472 | if (UserManager != null) |
||
473 | UserManager.AddUser(part.CreatorID, part.CreatorData); |
||
474 | |||
475 | if (!ResolveUserUuid(scene, part.OwnerID)) |
||
476 | part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
477 | |||
478 | if (!ResolveUserUuid(scene, part.LastOwnerID)) |
||
479 | part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
480 | |||
481 | if (!ResolveGroupUuid(part.GroupID)) |
||
482 | part.GroupID = UUID.Zero; |
||
483 | |||
484 | // And zap any troublesome sit target information |
||
485 | // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); |
||
486 | // part.SitTargetPosition = new Vector3(0, 0, 0); |
||
487 | |||
488 | // Fix ownership/creator of inventory items |
||
489 | // Not doing so results in inventory items |
||
490 | // being no copy/no mod for everyone |
||
491 | lock (part.TaskInventory) |
||
492 | { |
||
493 | TaskInventoryDictionary inv = part.TaskInventory; |
||
494 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) |
||
495 | { |
||
496 | if (!ResolveUserUuid(scene, kvp.Value.OwnerID)) |
||
497 | { |
||
498 | kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
499 | } |
||
500 | |||
501 | if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty) |
||
502 | { |
||
503 | if (!ResolveUserUuid(scene, kvp.Value.CreatorID)) |
||
504 | kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; |
||
505 | } |
||
506 | |||
507 | if (UserManager != null) |
||
508 | UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); |
||
509 | |||
510 | if (!ResolveGroupUuid(kvp.Value.GroupID)) |
||
511 | kvp.Value.GroupID = UUID.Zero; |
||
512 | } |
||
513 | } |
||
514 | } |
||
515 | |||
516 | if (scene.AddRestoredSceneObject(sceneObject, true, false)) |
||
517 | { |
||
518 | sceneObjectsLoadedCount++; |
||
519 | sceneObject.CreateScriptInstances(0, false, scene.DefaultScriptEngine, 0); |
||
520 | sceneObject.ResumeScripts(); |
||
521 | } |
||
522 | } |
||
523 | |||
524 | m_log.InfoFormat("[ARCHIVER]: Restored {0} scene objects to the scene", sceneObjectsLoadedCount); |
||
525 | |||
526 | int ignoredObjects = serialisedSceneObjects.Count - sceneObjectsLoadedCount; |
||
527 | |||
528 | if (ignoredObjects > 0) |
||
529 | m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene", ignoredObjects); |
||
530 | |||
531 | if (oldTelehubUUID != UUID.Zero) |
||
532 | { |
||
533 | m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); |
||
534 | scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; |
||
535 | scene.RegionInfo.RegionSettings.ClearSpawnPoints(); |
||
536 | } |
||
537 | } |
||
538 | |||
539 | /// <summary> |
||
540 | /// Load serialized parcels. |
||
541 | /// </summary> |
||
542 | /// <param name="scene"></param> |
||
543 | /// <param name="serialisedParcels"></param> |
||
544 | protected void LoadParcels(Scene scene, List<string> serialisedParcels) |
||
545 | { |
||
546 | // Reload serialized parcels |
||
547 | m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count); |
||
548 | List<LandData> landData = new List<LandData>(); |
||
549 | foreach (string serialisedParcel in serialisedParcels) |
||
550 | { |
||
551 | LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); |
||
552 | |||
553 | // Validate User and Group UUID's |
||
554 | |||
555 | if (parcel.IsGroupOwned) |
||
556 | { |
||
557 | if (!ResolveGroupUuid(parcel.GroupID)) |
||
558 | { |
||
559 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
||
560 | parcel.GroupID = UUID.Zero; |
||
561 | parcel.IsGroupOwned = false; |
||
562 | } |
||
563 | } |
||
564 | else |
||
565 | { |
||
566 | if (!ResolveUserUuid(scene, parcel.OwnerID)) |
||
567 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
||
568 | |||
569 | if (!ResolveGroupUuid(parcel.GroupID)) |
||
570 | parcel.GroupID = UUID.Zero; |
||
571 | } |
||
572 | |||
573 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); |
||
574 | foreach (LandAccessEntry entry in parcel.ParcelAccessList) |
||
575 | { |
||
576 | if (ResolveUserUuid(scene, entry.AgentID)) |
||
577 | accessList.Add(entry); |
||
578 | // else, drop this access rule |
||
579 | } |
||
580 | parcel.ParcelAccessList = accessList; |
||
581 | |||
582 | // m_log.DebugFormat( |
||
583 | // "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}", |
||
584 | // parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area); |
||
585 | |||
586 | landData.Add(parcel); |
||
587 | } |
||
588 | |||
589 | if (!m_merge) |
||
590 | { |
||
591 | bool setupDefaultParcel = (landData.Count == 0); |
||
592 | scene.LandChannel.Clear(setupDefaultParcel); |
||
593 | } |
||
594 | |||
595 | scene.EventManager.TriggerIncomingLandDataFromStorage(landData); |
||
596 | m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count); |
||
597 | } |
||
598 | |||
599 | /// <summary> |
||
600 | /// Look up the given user id to check whether it's one that is valid for this grid. |
||
601 | /// </summary> |
||
602 | /// <param name="scene"></param> |
||
603 | /// <param name="uuid"></param> |
||
604 | /// <returns></returns> |
||
605 | private bool ResolveUserUuid(Scene scene, UUID uuid) |
||
606 | { |
||
607 | lock (m_validUserUuids) |
||
608 | { |
||
609 | if (!m_validUserUuids.ContainsKey(uuid)) |
||
610 | { |
||
611 | // Note: we call GetUserAccount() inside the lock because this UserID is likely |
||
612 | // to occur many times, and we only want to query the users service once. |
||
613 | UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); |
||
614 | m_validUserUuids.Add(uuid, account != null); |
||
615 | } |
||
616 | |||
617 | return m_validUserUuids[uuid]; |
||
618 | } |
||
619 | } |
||
620 | |||
621 | /// <summary> |
||
622 | /// Look up the given group id to check whether it's one that is valid for this grid. |
||
623 | /// </summary> |
||
624 | /// <param name="uuid"></param> |
||
625 | /// <returns></returns> |
||
626 | private bool ResolveGroupUuid(UUID uuid) |
||
627 | { |
||
628 | if (uuid == UUID.Zero) |
||
629 | return true; // this means the object has no group |
||
630 | |||
631 | lock (m_validGroupUuids) |
||
632 | { |
||
633 | if (!m_validGroupUuids.ContainsKey(uuid)) |
||
634 | { |
||
635 | bool exists; |
||
636 | if (m_groupsModule == null) |
||
637 | { |
||
638 | exists = false; |
||
639 | } |
||
640 | else |
||
641 | { |
||
642 | // Note: we call GetGroupRecord() inside the lock because this GroupID is likely |
||
643 | // to occur many times, and we only want to query the groups service once. |
||
644 | exists = (m_groupsModule.GetGroupRecord(uuid) != null); |
||
645 | } |
||
646 | m_validGroupUuids.Add(uuid, exists); |
||
647 | } |
||
648 | |||
649 | return m_validGroupUuids[uuid]; |
||
650 | } |
||
651 | } |
||
652 | |||
653 | /// Load an asset |
||
654 | /// </summary> |
||
655 | /// <param name="assetFilename"></param> |
||
656 | /// <param name="data"></param> |
||
657 | /// <returns>true if asset was successfully loaded, false otherwise</returns> |
||
658 | private bool LoadAsset(string assetPath, byte[] data) |
||
659 | { |
||
660 | // Right now we're nastily obtaining the UUID from the filename |
||
661 | string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); |
||
662 | int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR); |
||
663 | |||
664 | if (i == -1) |
||
665 | { |
||
666 | m_log.ErrorFormat( |
||
667 | "[ARCHIVER]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping", |
||
668 | assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR); |
||
669 | |||
670 | return false; |
||
671 | } |
||
672 | |||
673 | string extension = filename.Substring(i); |
||
674 | string uuid = filename.Remove(filename.Length - extension.Length); |
||
675 | |||
676 | if (m_assetService.GetMetadata(uuid) != null) |
||
677 | { |
||
678 | // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid); |
||
679 | return true; |
||
680 | } |
||
681 | |||
682 | if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) |
||
683 | { |
||
684 | sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; |
||
685 | |||
686 | if (assetType == (sbyte)AssetType.Unknown) |
||
687 | m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); |
||
688 | |||
689 | //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); |
||
690 | |||
691 | AssetBase asset = new AssetBase(new UUID(uuid), String.Empty, assetType, UUID.Zero.ToString()); |
||
692 | asset.Data = data; |
||
693 | |||
694 | // We're relying on the asset service to do the sensible thing and not store the asset if it already |
||
695 | // exists. |
||
696 | m_assetService.Store(asset); |
||
697 | |||
698 | /** |
||
699 | * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so |
||
700 | * it might be best done when dearchive takes place on a separate thread |
||
701 | if (asset.Type=AssetType.Texture) |
||
702 | { |
||
703 | IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); |
||
704 | if (cacheLayerDecode != null) |
||
705 | cacheLayerDecode.syncdecode(asset.FullID, asset.Data); |
||
706 | } |
||
707 | */ |
||
708 | |||
709 | return true; |
||
710 | } |
||
711 | else |
||
712 | { |
||
713 | m_log.ErrorFormat( |
||
714 | "[ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}", |
||
715 | assetPath, extension); |
||
716 | |||
717 | return false; |
||
718 | } |
||
719 | } |
||
720 | |||
721 | /// <summary> |
||
722 | /// Load region settings data |
||
723 | /// </summary> |
||
724 | /// <param name="scene"></param> |
||
725 | /// <param name="settingsPath"></param> |
||
726 | /// <param name="data"></param> |
||
727 | /// <param name="dearchivedScenes"></param> |
||
728 | /// <returns> |
||
729 | /// true if settings were loaded successfully, false otherwise |
||
730 | /// </returns> |
||
731 | private bool LoadRegionSettings(Scene scene, string settingsPath, byte[] data, DearchiveScenesInfo dearchivedScenes) |
||
732 | { |
||
733 | RegionSettings loadedRegionSettings; |
||
734 | |||
735 | try |
||
736 | { |
||
737 | loadedRegionSettings = RegionSettingsSerializer.Deserialize(data); |
||
738 | } |
||
739 | catch (Exception e) |
||
740 | { |
||
741 | m_log.ErrorFormat( |
||
742 | "[ARCHIVER]: Could not parse region settings file {0}. Ignoring. Exception was {1}", |
||
743 | settingsPath, e); |
||
744 | return false; |
||
745 | } |
||
746 | |||
747 | RegionSettings currentRegionSettings = scene.RegionInfo.RegionSettings; |
||
748 | |||
749 | currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit; |
||
750 | currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage; |
||
751 | currentRegionSettings.AllowLandJoinDivide = loadedRegionSettings.AllowLandJoinDivide; |
||
752 | currentRegionSettings.AllowLandResell = loadedRegionSettings.AllowLandResell; |
||
753 | currentRegionSettings.BlockFly = loadedRegionSettings.BlockFly; |
||
754 | currentRegionSettings.BlockShowInSearch = loadedRegionSettings.BlockShowInSearch; |
||
755 | currentRegionSettings.BlockTerraform = loadedRegionSettings.BlockTerraform; |
||
756 | currentRegionSettings.DisableCollisions = loadedRegionSettings.DisableCollisions; |
||
757 | currentRegionSettings.DisablePhysics = loadedRegionSettings.DisablePhysics; |
||
758 | currentRegionSettings.DisableScripts = loadedRegionSettings.DisableScripts; |
||
759 | currentRegionSettings.Elevation1NE = loadedRegionSettings.Elevation1NE; |
||
760 | currentRegionSettings.Elevation1NW = loadedRegionSettings.Elevation1NW; |
||
761 | currentRegionSettings.Elevation1SE = loadedRegionSettings.Elevation1SE; |
||
762 | currentRegionSettings.Elevation1SW = loadedRegionSettings.Elevation1SW; |
||
763 | currentRegionSettings.Elevation2NE = loadedRegionSettings.Elevation2NE; |
||
764 | currentRegionSettings.Elevation2NW = loadedRegionSettings.Elevation2NW; |
||
765 | currentRegionSettings.Elevation2SE = loadedRegionSettings.Elevation2SE; |
||
766 | currentRegionSettings.Elevation2SW = loadedRegionSettings.Elevation2SW; |
||
767 | currentRegionSettings.FixedSun = loadedRegionSettings.FixedSun; |
||
768 | currentRegionSettings.SunPosition = loadedRegionSettings.SunPosition; |
||
769 | currentRegionSettings.ObjectBonus = loadedRegionSettings.ObjectBonus; |
||
770 | currentRegionSettings.RestrictPushing = loadedRegionSettings.RestrictPushing; |
||
771 | currentRegionSettings.TerrainLowerLimit = loadedRegionSettings.TerrainLowerLimit; |
||
772 | currentRegionSettings.TerrainRaiseLimit = loadedRegionSettings.TerrainRaiseLimit; |
||
773 | currentRegionSettings.TerrainTexture1 = loadedRegionSettings.TerrainTexture1; |
||
774 | currentRegionSettings.TerrainTexture2 = loadedRegionSettings.TerrainTexture2; |
||
775 | currentRegionSettings.TerrainTexture3 = loadedRegionSettings.TerrainTexture3; |
||
776 | currentRegionSettings.TerrainTexture4 = loadedRegionSettings.TerrainTexture4; |
||
777 | currentRegionSettings.UseEstateSun = loadedRegionSettings.UseEstateSun; |
||
778 | currentRegionSettings.WaterHeight = loadedRegionSettings.WaterHeight; |
||
779 | currentRegionSettings.TelehubObject = loadedRegionSettings.TelehubObject; |
||
780 | currentRegionSettings.ClearSpawnPoints(); |
||
781 | foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints()) |
||
782 | currentRegionSettings.AddSpawnPoint(sp); |
||
783 | |||
784 | currentRegionSettings.LoadedCreationDateTime = dearchivedScenes.LoadedCreationDateTime; |
||
785 | currentRegionSettings.LoadedCreationID = dearchivedScenes.GetOriginalRegionID(scene.RegionInfo.RegionID).ToString(); |
||
786 | |||
787 | currentRegionSettings.Save(); |
||
788 | |||
789 | scene.TriggerEstateSunUpdate(); |
||
790 | |||
791 | IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>(); |
||
792 | if (estateModule != null) |
||
793 | estateModule.sendRegionHandshakeToAll(); |
||
794 | |||
795 | return true; |
||
796 | } |
||
797 | |||
798 | /// <summary> |
||
799 | /// Load terrain data |
||
800 | /// </summary> |
||
801 | /// <param name="scene"></param> |
||
802 | /// <param name="terrainPath"></param> |
||
803 | /// <param name="data"></param> |
||
804 | /// <returns> |
||
805 | /// true if terrain was resolved successfully, false otherwise. |
||
806 | /// </returns> |
||
807 | private bool LoadTerrain(Scene scene, string terrainPath, byte[] data) |
||
808 | { |
||
809 | ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); |
||
810 | |||
811 | MemoryStream ms = new MemoryStream(data); |
||
812 | terrainModule.LoadFromStream(terrainPath, ms); |
||
813 | ms.Close(); |
||
814 | |||
815 | m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); |
||
816 | |||
817 | return true; |
||
818 | } |
||
819 | |||
820 | /// <summary> |
||
821 | /// Load oar control file |
||
822 | /// </summary> |
||
823 | /// <param name="path"></param> |
||
824 | /// <param name="data"></param> |
||
825 | /// <param name="dearchivedScenes"></param> |
||
826 | public DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes) |
||
827 | { |
||
828 | XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); |
||
829 | XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); |
||
830 | XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context); |
||
831 | |||
832 | // Loaded metadata will be empty if no information exists in the archive |
||
833 | dearchivedScenes.LoadedCreationDateTime = 0; |
||
834 | dearchivedScenes.DefaultOriginalID = ""; |
||
835 | |||
836 | bool multiRegion = false; |
||
837 | |||
838 | while (xtr.Read()) |
||
839 | { |
||
840 | if (xtr.NodeType == XmlNodeType.Element) |
||
841 | { |
||
842 | if (xtr.Name.ToString() == "archive") |
||
843 | { |
||
844 | int majorVersion = int.Parse(xtr["major_version"]); |
||
845 | int minorVersion = int.Parse(xtr["minor_version"]); |
||
846 | string version = string.Format("{0}.{1}", majorVersion, minorVersion); |
||
847 | |||
848 | if (majorVersion > MAX_MAJOR_VERSION) |
||
849 | { |
||
850 | throw new Exception( |
||
851 | string.Format( |
||
852 | "The OAR you are trying to load has major version number of {0} but this version of OpenSim can only load OARs with major version number {1} and below", |
||
853 | majorVersion, MAX_MAJOR_VERSION)); |
||
854 | } |
||
855 | |||
856 | m_log.InfoFormat("[ARCHIVER]: Loading OAR with version {0}", version); |
||
857 | } |
||
858 | if (xtr.Name.ToString() == "datetime") |
||
859 | { |
||
860 | int value; |
||
861 | if (Int32.TryParse(xtr.ReadElementContentAsString(), out value)) |
||
862 | dearchivedScenes.LoadedCreationDateTime = value; |
||
863 | } |
||
864 | else if (xtr.Name.ToString() == "row") |
||
865 | { |
||
866 | multiRegion = true; |
||
867 | dearchivedScenes.StartRow(); |
||
868 | } |
||
869 | else if (xtr.Name.ToString() == "region") |
||
870 | { |
||
871 | dearchivedScenes.StartRegion(); |
||
872 | } |
||
873 | else if (xtr.Name.ToString() == "id") |
||
874 | { |
||
875 | string id = xtr.ReadElementContentAsString(); |
||
876 | dearchivedScenes.DefaultOriginalID = id; |
||
877 | if (multiRegion) |
||
878 | dearchivedScenes.SetRegionOriginalID(id); |
||
879 | } |
||
880 | else if (xtr.Name.ToString() == "dir") |
||
881 | { |
||
882 | dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString()); |
||
883 | } |
||
884 | } |
||
885 | } |
||
886 | |||
887 | dearchivedScenes.MultiRegionFormat = multiRegion; |
||
888 | if (!multiRegion) |
||
889 | { |
||
890 | // Add the single scene |
||
891 | dearchivedScenes.StartRow(); |
||
892 | dearchivedScenes.StartRegion(); |
||
893 | dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID); |
||
894 | dearchivedScenes.SetRegionDirectory(""); |
||
895 | } |
||
896 | |||
897 | ControlFileLoaded = true; |
||
898 | |||
899 | return dearchivedScenes; |
||
900 | } |
||
901 | } |
||
902 | } |