OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ArchiveReadRequest.cs
Go to the documentation of this file.
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.CoreModules.World.Land;
44 using OpenSim.Region.Framework.Interfaces;
45 using OpenSim.Region.Framework.Scenes;
46 using OpenSim.Region.Framework.Scenes.Serialization;
47 using OpenSim.Services.Interfaces;
48 using System.Threading;
49 
50 namespace OpenSim.Region.CoreModules.World.Archiver
51 {
55  public class ArchiveReadRequest
56  {
57  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 
62  private class DearchiveContext
63  {
64  public Scene Scene { get; set; }
65 
66  public List<string> SerialisedSceneObjects { get; set; }
67 
68  public List<string> SerialisedParcels { get; set; }
69 
70  public List<SceneObjectGroup> SceneObjects { get; set; }
71 
72  public DearchiveContext(Scene scene)
73  {
74  Scene = scene;
75  SerialisedSceneObjects = new List<string>();
76  SerialisedParcels = new List<string>();
77  SceneObjects = new List<SceneObjectGroup>();
78  }
79  }
80 
81 
86  public static int MAX_MAJOR_VERSION = 1;
87 
91  public bool ControlFileLoaded { get; private set; }
92 
93  protected string m_loadPath;
94  protected Scene m_rootScene;
95  protected Stream m_loadStream;
96  protected Guid m_requestId;
97  protected string m_errorMessage;
98 
103  protected bool m_merge;
104 
108  protected bool m_forceTerrain;
109 
113  protected bool m_forceParcels;
114 
118  protected bool m_skipAssets;
119 
123  protected Vector3 m_displacement = Vector3.Zero;
124 
128  protected float m_rotation = 0f;
129 
133  protected Vector3 m_incomingRegionSize = new Vector3(256f, 256f, float.MaxValue);
134 
138  protected Vector3 m_rotationCenter = new Vector3(128f, 128f, 0f);
139 
143  protected Vector3 m_boundingOrigin = Vector3.Zero;
144 
148  protected Vector3 m_boundingSize = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, float.MaxValue);
149 
150  protected bool m_noObjects = false;
151  protected bool m_boundingBox = false;
152  protected bool m_debug = false;
153 
157  private IDictionary<UUID, bool> m_validUserUuids = new Dictionary<UUID, bool>();
158 
159  private IUserManagement m_UserMan;
160  private IUserManagement UserManager
161  {
162  get
163  {
164  if (m_UserMan == null)
165  {
166  m_UserMan = m_rootScene.RequestModuleInterface<IUserManagement>();
167  }
168  return m_UserMan;
169  }
170  }
171 
175  private IDictionary<UUID, bool> m_validGroupUuids = new Dictionary<UUID, bool>();
176 
177  private IGroupsModule m_groupsModule;
178 
179  private IAssetService m_assetService = null;
180 
181  private UUID m_defaultUser;
182 
183  public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary<string, object> options)
184  {
185  m_rootScene = scene;
186 
187  if (options.ContainsKey("default-user"))
188  {
189  m_defaultUser = (UUID)options["default-user"];
190  m_log.InfoFormat("Using User {0} as default user", m_defaultUser.ToString());
191  }
192  else
193  {
194  m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner;
195  }
196 
197  m_loadPath = loadPath;
198  try
199  {
200  m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress);
201  }
202  catch (EntryPointNotFoundException e)
203  {
204  m_log.ErrorFormat(
205  "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
206  + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
207  m_log.Error(e);
208  }
209 
210  m_errorMessage = String.Empty;
211 
212  m_merge = options.ContainsKey("merge");
213  m_forceTerrain = options.ContainsKey("force-terrain");
214  m_forceParcels = options.ContainsKey("force-parcels");
215  m_noObjects = options.ContainsKey("no-objects");
216  m_skipAssets = options.ContainsKey("skipAssets");
217  m_requestId = requestId;
218  m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero;
219  m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f;
220 
221  m_boundingOrigin = Vector3.Zero;
222  m_boundingSize = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, float.MaxValue);
223 
224  if (options.ContainsKey("bounding-origin"))
225  {
226  Vector3 boOption = (Vector3)options["bounding-origin"];
227  if (boOption != m_boundingOrigin)
228  {
229  m_boundingOrigin = boOption;
230  m_boundingBox = true;
231  }
232  }
233 
234  if (options.ContainsKey("bounding-size"))
235  {
236  Vector3 bsOption = (Vector3)options["bounding-size"];
237  bool clip = false;
238  if (bsOption.X <= 0 || bsOption.X > m_boundingSize.X)
239  {
240  bsOption.X = m_boundingSize.X;
241  clip = true;
242  }
243  if (bsOption.Y <= 0 || bsOption.Y > m_boundingSize.Y)
244  {
245  bsOption.Y = m_boundingSize.Y;
246  clip = true;
247  }
248  if (bsOption != m_boundingSize)
249  {
250  m_boundingSize = bsOption;
251  m_boundingBox = true;
252  }
253  if (clip) m_log.InfoFormat("[ARCHIVER]: The bounding cube specified is larger than the destination region! Clipping to {0}.", m_boundingSize.ToString());
254  }
255 
256  m_debug = options.ContainsKey("debug");
257 
258  // Zero can never be a valid user id (or group)
259  m_validUserUuids[UUID.Zero] = false;
260  m_validGroupUuids[UUID.Zero] = false;
261 
262  m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
263  m_assetService = m_rootScene.AssetService;
264  }
265 
266  public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary<string, object> options)
267  {
268  m_rootScene = scene;
269  m_loadPath = null;
270  m_loadStream = loadStream;
271  m_skipAssets = options.ContainsKey("skipAssets");
272  m_merge = options.ContainsKey("merge");
273  m_requestId = requestId;
274 
275  m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner;
276 
277  // Zero can never be a valid user id
278  m_validUserUuids[UUID.Zero] = false;
279 
280  m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
281  m_assetService = m_rootScene.AssetService;
282  }
283 
287  public void DearchiveRegion()
288  {
289  int successfulAssetRestores = 0;
290  int failedAssetRestores = 0;
291 
292  DearchiveScenesInfo dearchivedScenes;
293 
294  // We dearchive all the scenes at once, because the files in the TAR archive might be mixed.
295  // Therefore, we have to keep track of the dearchive context of all the scenes.
296  Dictionary<UUID, DearchiveContext> sceneContexts = new Dictionary<UUID, DearchiveContext>();
297 
298  string fullPath = "NONE";
299  TarArchiveReader archive = null;
300  byte[] data;
301  TarArchiveReader.TarEntryType entryType;
302 
303  try
304  {
305  FindAndLoadControlFile(out archive, out dearchivedScenes);
306 
307  while ((data = archive.ReadEntry(out fullPath, out entryType)) != null)
308  {
309  //m_log.DebugFormat(
310  // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length);
311 
312  if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
313  continue;
314 
315 
316  // Find the scene that this file belongs to
317 
318  Scene scene;
319  string filePath;
320  if (!dearchivedScenes.GetRegionFromPath(fullPath, out scene, out filePath))
321  continue; // this file belongs to a region that we're not loading
322 
323  DearchiveContext sceneContext = null;
324  if (scene != null)
325  {
326  if (!sceneContexts.TryGetValue(scene.RegionInfo.RegionID, out sceneContext))
327  {
328  sceneContext = new DearchiveContext(scene);
329  sceneContexts.Add(scene.RegionInfo.RegionID, sceneContext);
330  }
331  }
332 
333 
334  // Process the file
335 
336  if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH) && !m_noObjects)
337  {
338  sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
339  }
340  else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets)
341  {
342  if (LoadAsset(filePath, data))
343  successfulAssetRestores++;
344  else
345  failedAssetRestores++;
346 
347  if ((successfulAssetRestores + failedAssetRestores) % 250 == 0)
348  m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets...");
349  }
350  else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH) && (!m_merge || m_forceTerrain))
351  {
352  LoadTerrain(scene, filePath, data);
353  }
354  else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
355  {
356  LoadRegionSettings(scene, filePath, data, dearchivedScenes);
357  }
358  else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels))
359  {
360  sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data));
361  }
362  else if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
363  {
364  // Ignore, because we already read the control file
365  }
366  }
367 
368  //m_log.Debug("[ARCHIVER]: Reached end of archive");
369  }
370  catch (Exception e)
371  {
372  m_log.Error(
373  String.Format("[ARCHIVER]: Aborting load with error in archive file {0} ", fullPath), e);
374  m_errorMessage += e.ToString();
375  m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
376  return;
377  }
378  finally
379  {
380  if (archive != null)
381  archive.Close();
382  }
383 
384  if (!m_skipAssets)
385  {
386  m_log.InfoFormat("[ARCHIVER]: Restored {0} assets", successfulAssetRestores);
387 
388  if (failedAssetRestores > 0)
389  {
390  m_log.ErrorFormat("[ARCHIVER]: Failed to load {0} assets", failedAssetRestores);
391  m_errorMessage += String.Format("Failed to load {0} assets", failedAssetRestores);
392  }
393  }
394 
395  foreach (DearchiveContext sceneContext in sceneContexts.Values)
396  {
397  m_log.InfoFormat("[ARCHIVER]: Loading region {0}", sceneContext.Scene.RegionInfo.RegionName);
398 
399  if (!m_merge)
400  {
401  m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
402  sceneContext.Scene.DeleteAllSceneObjects();
403  }
404 
405  try
406  {
407  LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels);
408  LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects);
409 
410  // Inform any interested parties that the region has changed. We waited until now so that all
411  // of the region's objects will be loaded when we send this notification.
412  IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface<IEstateModule>();
413  if (estateModule != null)
414  estateModule.TriggerRegionInfoChange();
415  }
416  catch (Exception e)
417  {
418  m_log.Error("[ARCHIVER]: Error loading parcels or objects ", e);
419  m_errorMessage += e.ToString();
420  m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
421  return;
422  }
423  }
424 
425  // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so
426  // that users can enter the scene. If we allow the scripts to start in the loop above
427  // then they significantly increase the time until the OAR finishes loading.
428  WorkManager.RunInThread(o =>
429  {
430  Thread.Sleep(15000);
431  m_log.Info("[ARCHIVER]: Starting scripts in scene objects");
432 
433  foreach (DearchiveContext sceneContext in sceneContexts.Values)
434  {
435  foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects)
436  {
437  sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart
438  sceneObject.ResumeScripts();
439  }
440 
441  sceneContext.SceneObjects.Clear();
442  }
443  }, null, string.Format("ReadArchiveStartScripts (request {0})", m_requestId));
444 
445  m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive");
446 
447  m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, dearchivedScenes.GetLoadedScenes(), m_errorMessage);
448  }
449 
460  private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes)
461  {
462  archive = new TarArchiveReader(m_loadStream);
463  dearchivedScenes = new DearchiveScenesInfo();
464 
465  string filePath;
466  byte[] data;
467  TarArchiveReader.TarEntryType entryType;
468  bool firstFile = true;
469 
470  while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
471  {
472  if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
473  continue;
474 
475  if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
476  {
477  LoadControlFile(filePath, data, dearchivedScenes);
478 
479  // Find which scenes are available in the simulator
480  ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup();
481  SceneManager.Instance.ForEachScene(delegate(Scene scene2)
482  {
483  simulatorScenes.AddScene(scene2);
484  });
485  simulatorScenes.CalcSceneLocations();
486  dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes);
487 
488  // If the control file wasn't the first file then reset the read pointer
489  if (!firstFile)
490  {
491  m_log.Warn("[ARCHIVER]: Control file wasn't the first file in the archive");
492  if (m_loadStream.CanSeek)
493  {
494  m_loadStream.Seek(0, SeekOrigin.Begin);
495  }
496  else if (m_loadPath != null)
497  {
498  archive.Close();
499  archive = null;
500  m_loadStream.Close();
501  m_loadStream = null;
502  m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress);
503  archive = new TarArchiveReader(m_loadStream);
504  }
505  else
506  {
507  // There isn't currently a scenario where this happens, but it's best to add a check just in case
508  throw new Exception("[ARCHIVER]: Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking");
509  }
510  }
511 
512  return;
513  }
514 
515  firstFile = false;
516  }
517 
518  throw new Exception("[ARCHIVER]: Control file not found");
519  }
520 
524  protected void LoadObjects(Scene scene, List<string> serialisedSceneObjects, List<SceneObjectGroup> sceneObjects)
525  {
526  // Reload serialized prims
527  m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
528 
529  // Convert rotation to radians
530  double rotation = Math.PI * m_rotation / 180f;
531 
532  OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, (float)rotation);
533 
534  UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject;
535 
536  IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
537  int sceneObjectsLoadedCount = 0;
538  Vector3 boundingExtent = new Vector3(m_boundingOrigin.X + m_boundingSize.X, m_boundingOrigin.Y + m_boundingSize.Y, m_boundingOrigin.Z + m_boundingSize.Z);
539 
540  foreach (string serialisedSceneObject in serialisedSceneObjects)
541  {
542  /*
543  m_log.DebugFormat("[ARCHIVER]: Loading xml with raw size {0}", serialisedSceneObject.Length);
544 
545  // Really large xml files (multi megabyte) appear to cause
546  // memory problems
547  // when loading the xml. But don't enable this check yet
548 
549  if (serialisedSceneObject.Length > 5000000)
550  {
551  m_log.Error("[ARCHIVER]: Ignoring xml since size > 5000000);");
552  continue;
553  }
554  */
555 
556  SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
557 
558  Vector3 pos = sceneObject.AbsolutePosition;
559  if (m_debug)
560  m_log.DebugFormat("[ARCHIVER]: Loading object from OAR with original scene position {0}.", pos.ToString());
561 
562  // Happily this does not do much to the object since it hasn't been added to the scene yet
563  if (!sceneObject.IsAttachment)
564  {
565  if (m_rotation != 0f)
566  {
567  //fix the rotation center to the middle of the incoming region now as it's otherwise hopelessly confusing on varRegions
568  //as it only works with objects and terrain (using old Merge method) and not parcels
569  m_rotationCenter.X = m_incomingRegionSize.X / 2;
570  m_rotationCenter.Y = m_incomingRegionSize.Y / 2;
571 
572  // Rotate the object
573  sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation;
574  // Get object position relative to rotation axis
575  Vector3 offset = pos - m_rotationCenter;
576  // Rotate the object position
577  offset *= rot;
578  // Restore the object position back to relative to the region
579  pos = m_rotationCenter + offset;
580  if (m_debug) m_log.DebugFormat("[ARCHIVER]: After rotation, object from OAR is at scene position {0}.", pos.ToString());
581  }
582  if (m_boundingBox)
583  {
584  if (pos.X < m_boundingOrigin.X || pos.X >= boundingExtent.X
585  || pos.Y < m_boundingOrigin.Y || pos.Y >= boundingExtent.Y
586  || pos.Z < m_boundingOrigin.Z || pos.Z >= boundingExtent.Z)
587  {
588  if (m_debug) m_log.DebugFormat("[ARCHIVER]: Skipping object from OAR in scene because it's position {0} is outside of bounding cube.", pos.ToString());
589  continue;
590  }
591  //adjust object position to be relative to <0,0> so we can apply the displacement
592  pos.X -= m_boundingOrigin.X;
593  pos.Y -= m_boundingOrigin.Y;
594  }
595  if (m_displacement != Vector3.Zero)
596  {
597  pos += m_displacement;
598  if (m_debug) m_log.DebugFormat("[ARCHIVER]: After displacement, object from OAR is at scene position {0}.", pos.ToString());
599  }
600  sceneObject.AbsolutePosition = pos;
601  }
602  if (m_debug)
603  m_log.DebugFormat("[ARCHIVER]: Placing object from OAR in scene at position {0}. ", pos.ToString());
604 
605  bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero);
606 
607  // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
608  // on the same region server and multiple examples a single object archive to be imported
609  // to the same scene (when this is possible).
610  sceneObject.ResetIDs();
611 
612  if (isTelehub)
613  {
614  // Change the Telehub Object to the new UUID
615  scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID;
616  scene.RegionInfo.RegionSettings.Save();
617  oldTelehubUUID = UUID.Zero;
618  }
619 
620  ModifySceneObject(scene, sceneObject);
621 
622  if (scene.AddRestoredSceneObject(sceneObject, true, false))
623  {
624  sceneObjectsLoadedCount++;
625  sceneObject.CreateScriptInstances(0, false, scene.DefaultScriptEngine, 0);
626  sceneObject.ResumeScripts();
627  }
628  }
629 
630  m_log.InfoFormat("[ARCHIVER]: Restored {0} scene objects to the scene", sceneObjectsLoadedCount);
631 
632  int ignoredObjects = serialisedSceneObjects.Count - sceneObjectsLoadedCount;
633 
634  if (ignoredObjects > 0)
635  m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene or were out of bounds", ignoredObjects);
636 
637  if (oldTelehubUUID != UUID.Zero)
638  {
639  m_log.WarnFormat("[ARCHIVER]: Telehub object not found: {0}", oldTelehubUUID);
640  scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero;
641  scene.RegionInfo.RegionSettings.ClearSpawnPoints();
642  }
643  }
644 
649  private void ModifySceneObject(Scene scene, SceneObjectGroup sceneObject)
650  {
651  // Try to retain the original creator/owner/lastowner if their uuid is present on this grid
652  // or creator data is present. Otherwise, use the estate owner instead.
653  foreach (SceneObjectPart part in sceneObject.Parts)
654  {
655  if (string.IsNullOrEmpty(part.CreatorData))
656  {
657  if (!ResolveUserUuid(scene, part.CreatorID))
658  part.CreatorID = m_defaultUser;
659  }
660  if (UserManager != null)
661  UserManager.AddUser(part.CreatorID, part.CreatorData);
662 
663  if (!(ResolveUserUuid(scene, part.OwnerID) || ResolveGroupUuid(part.OwnerID)))
664  part.OwnerID = m_defaultUser;
665 
666  if (!(ResolveUserUuid(scene, part.LastOwnerID) || ResolveGroupUuid(part.LastOwnerID)))
667  part.LastOwnerID = m_defaultUser;
668 
669  if (!ResolveGroupUuid(part.GroupID))
670  part.GroupID = UUID.Zero;
671 
672  // And zap any troublesome sit target information
673  // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
674  // part.SitTargetPosition = new Vector3(0, 0, 0);
675 
676  // Fix ownership/creator of inventory items
677  // Not doing so results in inventory items
678  // being no copy/no mod for everyone
679  lock (part.TaskInventory)
680  {
681 /* avination code disabled for opensim
682  // And zap any troublesome sit target information
683  part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
684  part.SitTargetPosition = new Vector3(0, 0, 0);
685 */
686  // Fix ownership/creator of inventory items
687  // Not doing so results in inventory items
688  // being no copy/no mod for everyone
689  part.TaskInventory.LockItemsForRead(true);
690 
691  TaskInventoryDictionary inv = part.TaskInventory;
692  foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
693  {
694  if (!(ResolveUserUuid(scene, kvp.Value.OwnerID) || ResolveGroupUuid(kvp.Value.OwnerID)))
695  {
696  kvp.Value.OwnerID = m_defaultUser;
697  }
698 
699  if (string.IsNullOrEmpty(kvp.Value.CreatorData))
700  {
701  if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
702  kvp.Value.CreatorID = m_defaultUser;
703  }
704 
705  if (UserManager != null)
706  UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
707 
708  if (!ResolveGroupUuid(kvp.Value.GroupID))
709  kvp.Value.GroupID = UUID.Zero;
710  }
711  part.TaskInventory.LockItemsForRead(false);
712 
713  }
714  }
715  }
716 
722  protected void LoadParcels(Scene scene, List<string> serialisedParcels)
723  {
724  // Reload serialized parcels
725  m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count);
726  List<LandData> landData = new List<LandData>();
727  ILandObject landObject = scene.RequestModuleInterface<ILandObject>();
728  List<ILandObject> parcels;
729  Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f);
730  Vector2 displacement = new Vector2(m_displacement.X, m_displacement.Y);
731  Vector2 boundingOrigin = new Vector2(m_boundingOrigin.X, m_boundingOrigin.Y);
732  Vector2 boundingSize = new Vector2(m_boundingSize.X, m_boundingSize.Y);
733  Vector2 regionSize = new Vector2(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY);
734 
735  // Gather any existing parcels before we add any more. Later as we add parcels we can check if the new parcel
736  // data overlays any of the old data, and we can modify and remove (if empty) the old parcel so that there's no conflict
737  parcels = scene.LandChannel.AllParcels();
738 
739  foreach (string serialisedParcel in serialisedParcels)
740  {
741  LandData parcel = LandDataSerializer.Deserialize(serialisedParcel);
742  bool overrideRegionSize = true; //use the src land parcel data size not the dst region size
743  bool isEmptyNow;
744  Vector3 AABBMin;
745  Vector3 AABBMax;
746 
747  // create a new LandObject that we can use to manipulate the incoming source parcel data
748  // this is ok, but just beware that some of the LandObject functions (that we haven't used here) still
749  // assume we're always using the destination region size
750  LandData ld = new LandData();
751  landObject = new LandObject(ld, scene);
752  landObject.LandData = parcel;
753 
754  bool[,] srcLandBitmap = landObject.ConvertBytesToLandBitmap(overrideRegionSize);
755  if (landObject.IsLandBitmapEmpty(srcLandBitmap))
756  {
757  m_log.InfoFormat("[ARCHIVER]: Skipping source parcel {0} with GlobalID: {1} LocalID: {2} that has no claimed land.",
758  parcel.Name, parcel.GlobalID, parcel.LocalID);
759  continue;
760  }
761  //m_log.DebugFormat("[ARCHIVER]: Showing claimed land for source parcel: {0} with GlobalID: {1} LocalID: {2}.",
762  // parcel.Name, parcel.GlobalID, parcel.LocalID);
763  //landObject.DebugLandBitmap(srcLandBitmap);
764 
765  bool[,] dstLandBitmap = landObject.RemapLandBitmap(srcLandBitmap, displacement, m_rotation, boundingOrigin, boundingSize, regionSize, out isEmptyNow, out AABBMin, out AABBMax);
766  if (isEmptyNow)
767  {
768  m_log.WarnFormat("[ARCHIVER]: Not adding destination parcel {0} with GlobalID: {1} LocalID: {2} because, after applying rotation, bounding and displacement, it has no claimed land.",
769  parcel.Name, parcel.GlobalID, parcel.LocalID);
770  continue;
771  }
772  //m_log.DebugFormat("[ARCHIVER]: Showing claimed land for destination parcel: {0} with GlobalID: {1} LocalID: {2} after applying rotation, bounding and displacement.",
773  // parcel.Name, parcel.GlobalID, parcel.LocalID);
774  //landObject.DebugLandBitmap(dstLandBitmap);
775 
776  landObject.LandBitmap = dstLandBitmap;
777  parcel.Bitmap = landObject.ConvertLandBitmapToBytes();
778  parcel.AABBMin = AABBMin;
779  parcel.AABBMax = AABBMax;
780 
781  if (m_merge)
782  {
783  // give the remapped parcel a new GlobalID, in case we're using the same OAR twice and a bounding cube, displacement and --merge
784  parcel.GlobalID = UUID.Random();
785 
786  //now check if the area of this new incoming parcel overlays an area in any existing parcels
787  //and if so modify or lose the existing parcels
788  for (int i = 0; i < parcels.Count; i++)
789  {
790  if (parcels[i] != null)
791  {
792  bool[,] modLandBitmap = parcels[i].ConvertBytesToLandBitmap(overrideRegionSize);
793  modLandBitmap = parcels[i].RemoveFromLandBitmap(modLandBitmap, dstLandBitmap, out isEmptyNow, out AABBMin, out AABBMax);
794  if (isEmptyNow)
795  {
796  parcels[i] = null;
797  }
798  else
799  {
800  parcels[i].LandBitmap = modLandBitmap;
801  parcels[i].LandData.Bitmap = parcels[i].ConvertLandBitmapToBytes();
802  parcels[i].LandData.AABBMin = AABBMin;
803  parcels[i].LandData.AABBMax = AABBMax;
804  }
805  }
806  }
807  }
808 
809  // Validate User and Group UUID's
810 
811  if (!ResolveGroupUuid(parcel.GroupID))
812  parcel.GroupID = UUID.Zero;
813 
814  if (parcel.IsGroupOwned)
815  {
816  if (parcel.GroupID != UUID.Zero)
817  {
818  // In group-owned parcels, OwnerID=GroupID. This should already be the case, but let's make sure.
819  parcel.OwnerID = parcel.GroupID;
820  }
821  else
822  {
823  parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
824  parcel.IsGroupOwned = false;
825  }
826  }
827  else
828  {
829  if (!ResolveUserUuid(scene, parcel.OwnerID))
830  parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
831  }
832 
833  List<LandAccessEntry> accessList = new List<LandAccessEntry>();
834  foreach (LandAccessEntry entry in parcel.ParcelAccessList)
835  {
836  if (ResolveUserUuid(scene, entry.AgentID))
837  accessList.Add(entry);
838  // else, drop this access rule
839  }
840  parcel.ParcelAccessList = accessList;
841 
842  if (m_debug) m_log.DebugFormat("[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}",
843  parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area);
844 
845  landData.Add(parcel);
846  }
847 
848  if (m_merge)
849  {
850  for (int i = 0; i < parcels.Count; i++) //if merging then we need to also add back in any existing parcels
851  {
852  if (parcels[i] != null) landData.Add(parcels[i].LandData);
853  }
854  }
855 
856  m_log.InfoFormat("[ARCHIVER]: Clearing {0} parcels.", parcels.Count);
857  bool setupDefaultParcel = (landData.Count == 0);
858  scene.LandChannel.Clear(setupDefaultParcel);
859  scene.EventManager.TriggerIncomingLandDataFromStorage(landData);
860  m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count);
861  }
862 
869  private bool ResolveUserUuid(Scene scene, UUID uuid)
870  {
871  lock (m_validUserUuids)
872  {
873  if (!m_validUserUuids.ContainsKey(uuid))
874  {
875  // Note: we call GetUserAccount() inside the lock because this UserID is likely
876  // to occur many times, and we only want to query the users service once.
877  UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid);
878  m_validUserUuids.Add(uuid, account != null);
879  }
880 
881  return m_validUserUuids[uuid];
882  }
883  }
884 
890  private bool ResolveGroupUuid(UUID uuid)
891  {
892  lock (m_validGroupUuids)
893  {
894  if (!m_validGroupUuids.ContainsKey(uuid))
895  {
896  bool exists;
897  if (m_groupsModule == null)
898  {
899  exists = false;
900  }
901  else
902  {
903  // Note: we call GetGroupRecord() inside the lock because this GroupID is likely
904  // to occur many times, and we only want to query the groups service once.
905  exists = (m_groupsModule.GetGroupRecord(uuid) != null);
906  }
907  m_validGroupUuids.Add(uuid, exists);
908  }
909 
910  return m_validGroupUuids[uuid];
911  }
912  }
913 
919  private bool LoadAsset(string assetPath, byte[] data)
920  {
921  // Right now we're nastily obtaining the UUID from the filename
922  string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
923  int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR);
924 
925  if (i == -1)
926  {
927  m_log.ErrorFormat(
928  "[ARCHIVER]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping",
929  assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR);
930 
931  return false;
932  }
933 
934  string extension = filename.Substring(i);
935  string uuid = filename.Remove(filename.Length - extension.Length);
936 
937  if (m_assetService.GetMetadata(uuid) != null)
938  {
939  // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid);
940  return true;
941  }
942 
943  if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension))
944  {
945  sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension];
946 
947  if (assetType == (sbyte)AssetType.Unknown)
948  {
949  m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid);
950  }
951  else if (assetType == (sbyte)AssetType.Object)
952  {
953  data = SceneObjectSerializer.ModifySerializedObject(UUID.Parse(uuid), data,
954  sog =>
955  {
956  ModifySceneObject(m_rootScene, sog);
957  return true;
958  });
959 
960  if (data == null)
961  return false;
962  }
963 
964  //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType);
965 
966  AssetBase asset = new AssetBase(new UUID(uuid), String.Empty, assetType, UUID.Zero.ToString());
967  asset.Data = data;
968 
969  // We're relying on the asset service to do the sensible thing and not store the asset if it already
970  // exists.
971  m_assetService.Store(asset);
972 
984  return true;
985  }
986  else
987  {
988  m_log.ErrorFormat(
989  "[ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}",
990  assetPath, extension);
991 
992  return false;
993  }
994  }
995 
1006  private bool LoadRegionSettings(Scene scene, string settingsPath, byte[] data, DearchiveScenesInfo dearchivedScenes)
1007  {
1008  RegionSettings loadedRegionSettings;
1009 
1010  try
1011  {
1012  loadedRegionSettings = RegionSettingsSerializer.Deserialize(data);
1013  }
1014  catch (Exception e)
1015  {
1016  m_log.ErrorFormat(
1017  "[ARCHIVER]: Could not parse region settings file {0}. Ignoring. Exception was {1}",
1018  settingsPath, e);
1019  return false;
1020  }
1021 
1022  RegionSettings currentRegionSettings = scene.RegionInfo.RegionSettings;
1023 
1024  currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit;
1025  currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage;
1026  currentRegionSettings.AllowLandJoinDivide = loadedRegionSettings.AllowLandJoinDivide;
1027  currentRegionSettings.AllowLandResell = loadedRegionSettings.AllowLandResell;
1028  currentRegionSettings.BlockFly = loadedRegionSettings.BlockFly;
1029  currentRegionSettings.BlockShowInSearch = loadedRegionSettings.BlockShowInSearch;
1030  currentRegionSettings.BlockTerraform = loadedRegionSettings.BlockTerraform;
1031  currentRegionSettings.DisableCollisions = loadedRegionSettings.DisableCollisions;
1032  currentRegionSettings.DisablePhysics = loadedRegionSettings.DisablePhysics;
1033  currentRegionSettings.DisableScripts = loadedRegionSettings.DisableScripts;
1034  currentRegionSettings.Elevation1NE = loadedRegionSettings.Elevation1NE;
1035  currentRegionSettings.Elevation1NW = loadedRegionSettings.Elevation1NW;
1036  currentRegionSettings.Elevation1SE = loadedRegionSettings.Elevation1SE;
1037  currentRegionSettings.Elevation1SW = loadedRegionSettings.Elevation1SW;
1038  currentRegionSettings.Elevation2NE = loadedRegionSettings.Elevation2NE;
1039  currentRegionSettings.Elevation2NW = loadedRegionSettings.Elevation2NW;
1040  currentRegionSettings.Elevation2SE = loadedRegionSettings.Elevation2SE;
1041  currentRegionSettings.Elevation2SW = loadedRegionSettings.Elevation2SW;
1042  currentRegionSettings.FixedSun = loadedRegionSettings.FixedSun;
1043  currentRegionSettings.SunPosition = loadedRegionSettings.SunPosition;
1044  currentRegionSettings.ObjectBonus = loadedRegionSettings.ObjectBonus;
1045  currentRegionSettings.RestrictPushing = loadedRegionSettings.RestrictPushing;
1046  currentRegionSettings.TerrainLowerLimit = loadedRegionSettings.TerrainLowerLimit;
1047  currentRegionSettings.TerrainRaiseLimit = loadedRegionSettings.TerrainRaiseLimit;
1048  currentRegionSettings.TerrainTexture1 = loadedRegionSettings.TerrainTexture1;
1049  currentRegionSettings.TerrainTexture2 = loadedRegionSettings.TerrainTexture2;
1050  currentRegionSettings.TerrainTexture3 = loadedRegionSettings.TerrainTexture3;
1051  currentRegionSettings.TerrainTexture4 = loadedRegionSettings.TerrainTexture4;
1052  currentRegionSettings.UseEstateSun = loadedRegionSettings.UseEstateSun;
1053  currentRegionSettings.WaterHeight = loadedRegionSettings.WaterHeight;
1054  currentRegionSettings.TelehubObject = loadedRegionSettings.TelehubObject;
1055  currentRegionSettings.ClearSpawnPoints();
1056  foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints())
1057  currentRegionSettings.AddSpawnPoint(sp);
1058 
1059  currentRegionSettings.LoadedCreationDateTime = dearchivedScenes.LoadedCreationDateTime;
1060  currentRegionSettings.LoadedCreationID = dearchivedScenes.GetOriginalRegionID(scene.RegionInfo.RegionID).ToString();
1061 
1062  currentRegionSettings.Save();
1063 
1064  scene.TriggerEstateSunUpdate();
1065 
1066  IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
1067  if (estateModule != null)
1068  estateModule.sendRegionHandshakeToAll();
1069 
1070  return true;
1071  }
1072 
1082  private bool LoadTerrain(Scene scene, string terrainPath, byte[] data)
1083  {
1084  ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
1085  using (MemoryStream ms = new MemoryStream(data))
1086  {
1087  if (m_displacement != Vector3.Zero || m_rotation != 0f || m_boundingBox)
1088  {
1089  Vector2 boundingOrigin = new Vector2(m_boundingOrigin.X, m_boundingOrigin.Y);
1090  Vector2 boundingSize = new Vector2(m_boundingSize.X, m_boundingSize.Y);
1091  terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, boundingOrigin, boundingSize, ms); ;
1092  }
1093  else
1094  {
1095  terrainModule.LoadFromStream(terrainPath, ms);
1096  }
1097  }
1098 
1099  m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath);
1100 
1101  return true;
1102  }
1103 
1110  public DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes)
1111  {
1112  XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
1113  XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
1114  XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context);
1115 
1116  // Loaded metadata will be empty if no information exists in the archive
1117  dearchivedScenes.LoadedCreationDateTime = 0;
1118  dearchivedScenes.DefaultOriginalID = "";
1119 
1120  bool multiRegion = false;
1121 
1122  while (xtr.Read())
1123  {
1124  if (xtr.NodeType == XmlNodeType.Element)
1125  {
1126  if (xtr.Name.ToString() == "archive")
1127  {
1128  int majorVersion = int.Parse(xtr["major_version"]);
1129  int minorVersion = int.Parse(xtr["minor_version"]);
1130  string version = string.Format("{0}.{1}", majorVersion, minorVersion);
1131 
1132  if (majorVersion > MAX_MAJOR_VERSION)
1133  {
1134  throw new Exception(
1135  string.Format(
1136  "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",
1137  majorVersion, MAX_MAJOR_VERSION));
1138  }
1139 
1140  m_log.InfoFormat("[ARCHIVER]: Loading OAR with version {0}", version);
1141  }
1142  else if (xtr.Name.ToString() == "datetime")
1143  {
1144  int value;
1145  if (Int32.TryParse(xtr.ReadElementContentAsString(), out value))
1146  dearchivedScenes.LoadedCreationDateTime = value;
1147  }
1148  else if (xtr.Name.ToString() == "row")
1149  {
1150  multiRegion = true;
1151  dearchivedScenes.StartRow();
1152  }
1153  else if (xtr.Name.ToString() == "region")
1154  {
1155  dearchivedScenes.StartRegion();
1156  }
1157  else if (xtr.Name.ToString() == "id")
1158  {
1159  string id = xtr.ReadElementContentAsString();
1160  dearchivedScenes.DefaultOriginalID = id;
1161  if(multiRegion)
1162  dearchivedScenes.SetRegionOriginalID(id);
1163  }
1164  else if (xtr.Name.ToString() == "dir")
1165  {
1166  dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString());
1167  }
1168  else if (xtr.Name.ToString() == "size_in_meters")
1169  {
1170  Vector3 value;
1171  string size = "<" + xtr.ReadElementContentAsString() + ",0>";
1172  if (Vector3.TryParse(size, out value))
1173  {
1174  m_incomingRegionSize = value;
1175  if(multiRegion)
1176  dearchivedScenes.SetRegionSize(m_incomingRegionSize);
1177  m_log.DebugFormat("[ARCHIVER]: Found region_size info {0}",
1178  m_incomingRegionSize.ToString());
1179  }
1180  }
1181  }
1182  }
1183 
1184  dearchivedScenes.MultiRegionFormat = multiRegion;
1185  if (!multiRegion)
1186  {
1187  // Add the single scene
1188  dearchivedScenes.StartRow();
1189  dearchivedScenes.StartRegion();
1190  dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID);
1191  dearchivedScenes.SetRegionDirectory("");
1192  dearchivedScenes.SetRegionSize(m_incomingRegionSize);
1193  }
1194 
1195  ControlFileLoaded = true;
1196 
1197  return dearchivedScenes;
1198  }
1199  }
1200 }
Temporary code to do the bare minimum required to read a tar archive for our purposes ...
A group of regions arranged in a rectangle, possibly with holes.
const uint MaximumRegionSize
Definition: Constants.cs:39
Constants for the archiving module
OpenSim.Framework.Serialization.TarArchiveReader TarArchiveReader
uint RegionSizeX
X dimension of the region.
Definition: RegionInfo.cs:161
A dictionary containing task inventory items. Indexed by item UUID.
uint RegionSizeY
X dimension of the region.
Definition: RegionInfo.cs:169
OpenSim.Framework.RegionSettings RegionSettings
void AddSpawnPoint(SpawnPoint point)
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
static readonly IDictionary< string, sbyte > EXTENSION_TO_ASSET_TYPE
void LoadParcels(Scene scene, List< string > serialisedParcels)
Load serialized parcels.
Definition: LandData.cs:37
Ionic.Zlib.GZipStream GZipStream
Asset class. All Assets are reference by this class or a class derived from this class ...
Definition: AssetBase.cs:49
Keeps track of a specific piece of land's information
Definition: LandObject.cs:43
ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary< string, object > options)
DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes)
Load oar control file
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
UUID GroupID
Unique ID of the Group that owns
Definition: LandData.cs:342
string CreatorData
Data about the creator in the form home_url;name
Details of a Parcel of land
Definition: LandData.cs:47
void LoadObjects(Scene scene, List< string > serialisedSceneObjects, List< SceneObjectGroup > sceneObjects)
Load serialized scene objects.
UUID AgentID
Definition: LandData.cs:39
bool IsGroupOwned
Returns true if the Land Parcel is owned by a group
Definition: LandData.cs:357
ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary< string, object > options)
List< SpawnPoint > SpawnPoints()
void DearchiveRegion()
Dearchive the region embodied in this request.
This maintains the relationship between a UUID and a user name.
bool IsAttachment
Is this scene object acting as an attachment?
UUID OwnerID
Owner Avatar or Group of the parcel. Naturally, all land masses must be owned by someone ...
Definition: LandData.cs:551