clockwerk-opensim – Blame information for rev 1

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