/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenSim.Region.Framework.Scenes;
using OpenMetaverse;
using System.Drawing;
using log4net;
using System.Reflection;
using OpenSim.Framework.Serialization;
namespace OpenSim.Region.CoreModules.World.Archiver
{
///
/// The regions included in an OAR file.
///
public class DearchiveScenesInfo
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
///
/// One region in the archive.
///
public class RegionInfo
{
///
/// The subdirectory in which the region is stored.
///
public string Directory { get; set; }
///
/// The region's coordinates (relative to the South-West corner of the block).
///
public Point Location { get; set; }
///
/// The UUID of the original scene from which this archived region was saved.
///
public string OriginalID { get; set; }
///
/// The scene in the current simulator into which this region is loaded.
/// If null then the region doesn't have a corresponding scene, and it won't be loaded.
///
public Scene Scene { get; set; }
///
/// The size of the region being loaded.
///
public Vector3 RegionSize { get; set; }
public RegionInfo()
{
RegionSize = new Vector3(256f,256f,float.MaxValue);
}
}
///
/// Whether this archive uses the multi-region format.
///
public Boolean MultiRegionFormat { get; set; }
///
/// Maps (Region directory -> region)
///
protected Dictionary m_directory2region = new Dictionary();
///
/// Maps (UUID of the scene in the simulator where the region will be loaded -> region)
///
protected Dictionary m_newId2region = new Dictionary();
public int LoadedCreationDateTime { get; set; }
public string DefaultOriginalID { get; set; }
// These variables are used while reading the archive control file
protected int? m_curY = null;
protected int? m_curX = null;
protected RegionInfo m_curRegion;
public DearchiveScenesInfo()
{
MultiRegionFormat = false;
}
// The following methods are used while reading the archive control file
public void StartRow()
{
m_curY = (m_curY == null) ? 0 : m_curY + 1;
m_curX = null;
}
public void StartRegion()
{
m_curX = (m_curX == null) ? 0 : m_curX + 1;
// Note: this doesn't mean we have a real region in this location; this could just be a "hole"
}
public void SetRegionOriginalID(string id)
{
m_curRegion = new RegionInfo();
int x = (int)((m_curX == null) ? 0 : m_curX);
int y = (int)((m_curY == null) ? 0 : m_curY);
m_curRegion.Location = new Point(x, y);
m_curRegion.OriginalID = id;
// 'curRegion' will be saved in 'm_directory2region' when SetRegionDir() is called
}
public void SetRegionDirectory(string directory)
{
if(m_curRegion != null)
{
m_curRegion.Directory = directory;
m_directory2region[directory] = m_curRegion;
}
}
public void SetRegionSize(Vector3 size)
{
if(m_curRegion != null)
m_curRegion.RegionSize = size;
}
///
/// Sets all the scenes present in the simulator.
///
///
/// This method matches regions in the archive to scenes in the simulator according to
/// their relative position. We only load regions if there's an existing Scene in the
/// grid location where the region should be loaded.
///
/// The scene where the Load OAR operation was run
/// All the scenes in the simulator
public void SetSimulatorScenes(Scene rootScene, ArchiveScenesGroup simulatorScenes)
{
foreach (RegionInfo archivedRegion in m_directory2region.Values)
{
Point location = new Point((int)rootScene.RegionInfo.RegionLocX,
(int)rootScene.RegionInfo.RegionLocY);
location.Offset(archivedRegion.Location);
Scene scene;
if (simulatorScenes.TryGetScene(location, out scene))
{
archivedRegion.Scene = scene;
m_newId2region[scene.RegionInfo.RegionID] = archivedRegion;
}
else
{
m_log.WarnFormat("[ARCHIVER]: Not loading archived region {0} because there's no existing region at location {1},{2}",
archivedRegion.Directory, location.X, location.Y);
}
}
}
///
/// Returns the archived region according to the path of a file in the archive.
/// Also, converts the full path into a path that is relative to the region's directory.
///
/// The path of a file in the archive
/// The corresponding Scene, or null if none
/// The path relative to the region's directory. (Or the original
/// path, if this file doesn't belong to a region.)
/// True: use this file; False: skip it
public bool GetRegionFromPath(string fullPath, out Scene scene, out string relativePath)
{
scene = null;
relativePath = fullPath;
if (!MultiRegionFormat)
{
if (m_newId2region.Count > 0)
scene = m_newId2region.First().Value.Scene;
return true;
}
if (!fullPath.StartsWith(ArchiveConstants.REGIONS_PATH))
return true; // this file doesn't belong to a region
string[] parts = fullPath.Split(new Char[] { '/' }, 3);
if (parts.Length != 3)
return false;
string regionDirectory = parts[1];
relativePath = parts[2];
RegionInfo region;
if (m_directory2region.TryGetValue(regionDirectory, out region))
{
scene = region.Scene;
return (scene != null);
}
else
{
return false;
}
}
///
/// Returns the original UUID of a region (from the simulator where the OAR was saved),
/// given the UUID of the scene it was loaded into in the current simulator.
///
///
///
public string GetOriginalRegionID(UUID newID)
{
RegionInfo region;
if (m_newId2region.TryGetValue(newID, out region))
return region.OriginalID;
else
return DefaultOriginalID;
}
///
/// Returns the scenes that have been (or will be) loaded.
///
///
public List GetLoadedScenes()
{
return m_newId2region.Keys.ToList();
}
public int GetScenesCount()
{
return m_directory2region.Count;
}
}
}