Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

bulletsim
Diva Canto 2011-05-26 15:52:34 -07:00
commit b17afe43c4
18 changed files with 499 additions and 111 deletions

View File

@ -267,12 +267,13 @@ namespace OpenSim
m_console.Commands.AddCommand("region", false, "save oar", m_console.Commands.AddCommand("region", false, "save oar",
//"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]", //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]",
"save oar [-p|--profile=<url>] [<OAR path>]", "save oar [-p|--profile=<url>] [--noassets] [<OAR path>]",
"Save a region's data to an OAR archive.", "Save a region's data to an OAR archive.",
// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine // "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
"-p|--profile=<url> adds the url of the profile service to the saved user information" + Environment.NewLine "-p|--profile=<url> adds the url of the profile service to the saved user information." + Environment.NewLine
+ "The OAR path must be a filesystem path." + " The OAR path must be a filesystem path."
+ " If this is not given then the oar is saved to region.oar in the current directory.", + " If this is not given then the oar is saved to region.oar in the current directory." + Environment.NewLine
+ "--noassets stops assets being saved to the OAR.",
SaveOar); SaveOar);
m_console.Commands.AddCommand("region", false, "edit scale", m_console.Commands.AddCommand("region", false, "edit scale",

View File

@ -46,6 +46,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Determine whether this archive will save assets. Default is true.
/// </summary>
public bool SaveAssets { get; set; }
/// <value> /// <value>
/// Used to select all inventory nodes in a folder but not the folder itself /// Used to select all inventory nodes in a folder but not the folder itself
/// </value> /// </value>
@ -112,6 +117,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
m_invPath = invPath; m_invPath = invPath;
m_saveStream = saveStream; m_saveStream = saveStream;
m_assetGatherer = new UuidGatherer(m_scene.AssetService); m_assetGatherer = new UuidGatherer(m_scene.AssetService);
SaveAssets = true;
} }
protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
@ -150,7 +157,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
string serialization = UserInventoryItemSerializer.Serialize(inventoryItem, options, userAccountService); string serialization = UserInventoryItemSerializer.Serialize(inventoryItem, options, userAccountService);
m_archiveWriter.WriteFile(filename, serialization); m_archiveWriter.WriteFile(filename, serialization);
m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, m_assetUuids); if (SaveAssets)
m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, m_assetUuids);
} }
/// <summary> /// <summary>
@ -195,6 +203,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
/// </summary> /// </summary>
public void Execute(Dictionary<string, object> options, IUserAccountService userAccountService) public void Execute(Dictionary<string, object> options, IUserAccountService userAccountService)
{ {
if (options.ContainsKey("noassets") && (bool)options["noassets"])
SaveAssets = false;
try try
{ {
InventoryFolderBase inventoryFolder = null; InventoryFolderBase inventoryFolder = null;
@ -286,11 +297,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
// Don't put all this profile information into the archive right now. // Don't put all this profile information into the archive right now.
//SaveUsers(); //SaveUsers();
new AssetsRequest( if (SaveAssets)
new AssetsArchiver(m_archiveWriter), {
m_assetUuids, m_scene.AssetService, m_log.DebugFormat("[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetUuids.Count);
m_scene.UserAccountService, m_scene.RegionInfo.ScopeID,
options, ReceivedAllAssets).Execute(); new AssetsRequest(
new AssetsArchiver(m_archiveWriter),
m_assetUuids, m_scene.AssetService,
m_scene.UserAccountService, m_scene.RegionInfo.ScopeID,
options, ReceivedAllAssets).Execute();
}
else
{
m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified");
ReceivedAllAssets(new List<UUID>(), new List<UUID>());
}
} }
catch (Exception) catch (Exception)
{ {
@ -387,19 +409,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
/// </summary> /// </summary>
/// <param name="options"></param> /// <param name="options"></param>
/// <returns></returns> /// <returns></returns>
public static string CreateControlFile(Dictionary<string, object> options) public string CreateControlFile(Dictionary<string, object> options)
{ {
int majorVersion, minorVersion; int majorVersion, minorVersion;
if (options.ContainsKey("profile")) if (options.ContainsKey("profile"))
{ {
majorVersion = 1; majorVersion = 1;
minorVersion = 1; minorVersion = 2;
} }
else else
{ {
majorVersion = 0; majorVersion = 0;
minorVersion = 2; minorVersion = 3;
} }
m_log.InfoFormat("[INVENTORY ARCHIVER]: Creating version {0}.{1} IAR", majorVersion, minorVersion); m_log.InfoFormat("[INVENTORY ARCHIVER]: Creating version {0}.{1} IAR", majorVersion, minorVersion);
@ -411,6 +433,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
xtw.WriteStartElement("archive"); xtw.WriteStartElement("archive");
xtw.WriteAttributeString("major_version", majorVersion.ToString()); xtw.WriteAttributeString("major_version", majorVersion.ToString());
xtw.WriteAttributeString("minor_version", minorVersion.ToString()); xtw.WriteAttributeString("minor_version", minorVersion.ToString());
xtw.WriteElementString("assets_included", SaveAssets.ToString());
xtw.WriteEndElement(); xtw.WriteEndElement();
xtw.Flush(); xtw.Flush();

View File

@ -122,7 +122,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
scene.AddCommand( scene.AddCommand(
this, "save iar", this, "save iar",
"save iar [--p|-profile=<url>] <first> <last> <inventory path> <password> [<IAR path>] [--v|-verbose]", "save iar [--p|-profile=<url>] [--noassets] <first> <last> <inventory path> <password> [<IAR path>] [--v|-verbose]",
"Save user inventory archive (IAR).", "Save user inventory archive (IAR).",
"<first> is the user's first name." + Environment.NewLine "<first> is the user's first name." + Environment.NewLine
+ "<last> is the user's last name." + Environment.NewLine + "<last> is the user's last name." + Environment.NewLine
@ -130,6 +130,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
+ "-p|--profile=<url> adds the url of the profile service to the saved user information." + Environment.NewLine + "-p|--profile=<url> adds the url of the profile service to the saved user information." + Environment.NewLine
+ "-c|--creators preserves information about foreign creators." + Environment.NewLine + "-c|--creators preserves information about foreign creators." + Environment.NewLine
+ "-v|--verbose extra debug messages." + Environment.NewLine + "-v|--verbose extra debug messages." + Environment.NewLine
+ "--noassets stops assets being saved to the IAR."
+ "<IAR path> is the filesystem path at which to save the IAR." + "<IAR path> is the filesystem path at which to save the IAR."
+ string.Format(" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME), + string.Format(" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME),
HandleSaveInvConsoleCommand); HandleSaveInvConsoleCommand);
@ -398,6 +399,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
ops.Add("p|profile=", delegate(string v) { options["profile"] = v; }); ops.Add("p|profile=", delegate(string v) { options["profile"] = v; });
ops.Add("v|verbose", delegate(string v) { options["verbose"] = v; }); ops.Add("v|verbose", delegate(string v) { options["verbose"] = v; });
ops.Add("c|creators", delegate(string v) { options["creators"] = v; }); ops.Add("c|creators", delegate(string v) { options["creators"] = v; });
ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; });
List<string> mainParams = ops.Parse(cmdparams); List<string> mainParams = ops.Parse(cmdparams);
@ -406,7 +408,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (mainParams.Count < 6) if (mainParams.Count < 6)
{ {
m_log.Error( m_log.Error(
"[INVENTORY ARCHIVER]: usage is save iar [--p|-profile=<url>] <first name> <last name> <inventory path> <user password> [<save file path>]"); "[INVENTORY ARCHIVER]: usage is save iar [--p|-profile=<url>] [--noassets] <first name> <last name> <inventory path> <user password> [<save file path>]");
return; return;
} }
@ -424,15 +426,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
"[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}", "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}",
savePath, invPath, firstName, lastName); savePath, invPath, firstName, lastName);
lock (m_pendingConsoleSaves)
m_pendingConsoleSaves.Add(id);
ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options); ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options);
} }
catch (InventoryArchiverException e) catch (InventoryArchiverException e)
{ {
m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message); m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message);
} }
lock (m_pendingConsoleSaves)
m_pendingConsoleSaves.Add(id);
} }
private void SaveInvConsoleCommandCompleted( private void SaveInvConsoleCommandCompleted(

View File

@ -123,11 +123,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
} }
/// <summary> /// <summary>
/// Test saving a single inventory item to a V0.1 OpenSim Inventory Archive /// Test saving a single inventory item to an IAR
/// (subject to change since there is no fixed format yet). /// (subject to change since there is no fixed format yet).
/// </summary> /// </summary>
[Test] [Test]
public void TestSaveItemToIarV0_1() public void TestSaveItemToIar()
{ {
TestHelper.InMethod(); TestHelper.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();
@ -211,6 +211,106 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
} }
} }
// Assert.That(gotControlFile, Is.True, "No control file in archive");
Assert.That(gotObject1File, Is.True, "No item1 file in archive");
// Assert.That(gotObject2File, Is.True, "No object2 file in archive");
// TODO: Test presence of more files and contents of files.
}
/// <summary>
/// Test saving a single inventory item to an IAR without its asset
/// </summary>
[Test]
public void TestSaveItemToIarNoAssets()
{
TestHelper.InMethod();
// log4net.Config.XmlConfigurator.Configure();
// Create user
string userFirstName = "Jock";
string userLastName = "Stirrup";
string userPassword = "troll";
UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020");
UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword);
// Create asset
UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040");
SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50);
UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");
AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1);
m_scene.AssetService.Store(asset1);
// Create item
UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080");
string item1Name = "My Little Dog";
InventoryItemBase item1 = new InventoryItemBase();
item1.Name = item1Name;
item1.AssetID = asset1.FullID;
item1.ID = item1Id;
InventoryFolderBase objsFolder
= InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0];
item1.Folder = objsFolder.ID;
m_scene.AddInventoryItem(item1);
MemoryStream archiveWriteStream = new MemoryStream();
Dictionary<string, Object> options = new Dictionary<string, Object>();
options.Add("noassets", true);
// When we're not saving assets, archiving is being done synchronously.
m_archiverModule.ArchiveInventory(
Guid.NewGuid(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream, options);
byte[] archive = archiveWriteStream.ToArray();
MemoryStream archiveReadStream = new MemoryStream(archive);
TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
//bool gotControlFile = false;
bool gotObject1File = false;
//bool gotObject2File = false;
string expectedObject1FileName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1);
string expectedObject1FilePath = string.Format(
"{0}{1}",
ArchiveConstants.INVENTORY_PATH,
expectedObject1FileName);
string filePath;
TarArchiveReader.TarEntryType tarEntryType;
// Console.WriteLine("Reading archive");
while (tar.ReadEntry(out filePath, out tarEntryType) != null)
{
Console.WriteLine("Got {0}", filePath);
// if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
// {
// gotControlFile = true;
// }
if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml"))
{
// string fileName = filePath.Remove(0, "Objects/".Length);
//
// if (fileName.StartsWith(part1.Name))
// {
Assert.That(expectedObject1FilePath, Is.EqualTo(filePath));
gotObject1File = true;
// }
// else if (fileName.StartsWith(part2.Name))
// {
// Assert.That(fileName, Is.EqualTo(expectedObject2FileName));
// gotObject2File = true;
// }
}
else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
{
Assert.Fail("Found asset path in TestSaveItemToIarNoAssets()");
}
}
// Assert.That(gotControlFile, Is.True, "No control file in archive"); // Assert.That(gotControlFile, Is.True, "No control file in archive");
Assert.That(gotObject1File, Is.True, "No item1 file in archive"); Assert.That(gotObject1File, Is.True, "No item1 file in archive");
// Assert.That(gotObject2File, Is.True, "No object2 file in archive"); // Assert.That(gotObject2File, Is.True, "No object2 file in archive");

View File

@ -60,6 +60,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
/// </summary> /// </summary>
public static int MAX_MAJOR_VERSION = 0; public static int MAX_MAJOR_VERSION = 0;
/// <summary>
/// Determine whether this archive will save assets. Default is true.
/// </summary>
public bool SaveAssets { get; set; }
protected Scene m_scene; protected Scene m_scene;
protected Stream m_saveStream; protected Stream m_saveStream;
protected Guid m_requestId; protected Guid m_requestId;
@ -73,10 +78,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
/// <exception cref="System.IO.IOException"> /// <exception cref="System.IO.IOException">
/// If there was a problem opening a stream for the file specified by the savePath /// If there was a problem opening a stream for the file specified by the savePath
/// </exception> /// </exception>
public ArchiveWriteRequestPreparation(Scene scene, string savePath, Guid requestId) public ArchiveWriteRequestPreparation(Scene scene, string savePath, Guid requestId) : this(scene, requestId)
{ {
m_scene = scene;
try try
{ {
m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress); m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress);
@ -86,10 +89,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
m_log.ErrorFormat( m_log.ErrorFormat(
"[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
+ "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
m_log.Error(e); m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace);
} }
m_requestId = requestId;
} }
/// <summary> /// <summary>
@ -98,11 +99,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver
/// <param name="scene"></param> /// <param name="scene"></param>
/// <param name="saveStream">The stream to which to save data.</param> /// <param name="saveStream">The stream to which to save data.</param>
/// <param name="requestId">The id associated with this request</param> /// <param name="requestId">The id associated with this request</param>
public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream, Guid requestId) public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId)
{
m_saveStream = saveStream;
}
protected ArchiveWriteRequestPreparation(Scene scene, Guid requestId)
{ {
m_scene = scene; m_scene = scene;
m_saveStream = saveStream;
m_requestId = requestId; m_requestId = requestId;
SaveAssets = true;
} }
/// <summary> /// <summary>
@ -111,6 +118,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
/// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
public void ArchiveRegion(Dictionary<string, object> options) public void ArchiveRegion(Dictionary<string, object> options)
{ {
if (options.ContainsKey("noassets") && (bool)options["noassets"])
SaveAssets = false;
try try
{ {
Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>(); Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
@ -118,16 +128,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
EntityBase[] entities = m_scene.GetEntities(); EntityBase[] entities = m_scene.GetEntities();
List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
/*
foreach (ILandObject lo in m_scene.LandChannel.AllParcels())
{
if (name == lo.LandData.Name)
{
// This is the parcel we want
}
}
*/
// Filter entities so that we only have scene objects. // Filter entities so that we only have scene objects.
// FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
// end up having to do this // end up having to do this
@ -142,16 +142,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
} }
} }
UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService); if (SaveAssets)
foreach (SceneObjectGroup sceneObject in sceneObjects)
{ {
assetGatherer.GatherAssetUuids(sceneObject, assetUuids); UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService);
}
m_log.DebugFormat( foreach (SceneObjectGroup sceneObject in sceneObjects)
"[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", {
sceneObjects.Count, assetUuids.Count); assetGatherer.GatherAssetUuids(sceneObject, assetUuids);
}
m_log.DebugFormat(
"[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
sceneObjects.Count, assetUuids.Count);
}
else
{
m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
}
// Make sure that we also request terrain texture assets // Make sure that we also request terrain texture assets
RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings; RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings;
@ -188,10 +195,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver
archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options)); archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options));
m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
new AssetsRequest( if (SaveAssets)
new AssetsArchiver(archiveWriter), assetUuids, new AssetsRequest(
m_scene.AssetService, m_scene.UserAccountService, new AssetsArchiver(archiveWriter), assetUuids,
m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets).Execute(); m_scene.AssetService, m_scene.UserAccountService,
m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets).Execute();
else
awre.ReceivedAllAssets(new List<UUID>(), new List<UUID>());
} }
catch (Exception) catch (Exception)
{ {
@ -204,9 +214,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
/// Create the control file for the most up to date archive /// Create the control file for the most up to date archive
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string CreateControlFile(Dictionary<string, object> options) public string CreateControlFile(Dictionary<string, object> options)
{ {
int majorVersion = MAX_MAJOR_VERSION, minorVersion = 6; int majorVersion = MAX_MAJOR_VERSION, minorVersion = 7;
// //
// if (options.ContainsKey("version")) // if (options.ContainsKey("version"))
// { // {
@ -258,6 +268,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
xtw.WriteElementString("id", UUID.Random().ToString()); xtw.WriteElementString("id", UUID.Random().ToString());
xtw.WriteEndElement(); xtw.WriteEndElement();
xtw.WriteElementString("assets_included", SaveAssets.ToString());
xtw.WriteEndElement(); xtw.WriteEndElement();
xtw.Flush(); xtw.Flush();

View File

@ -127,6 +127,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
OptionSet ops = new OptionSet(); OptionSet ops = new OptionSet();
// ops.Add("v|version=", delegate(string v) { options["version"] = v; }); // ops.Add("v|version=", delegate(string v) { options["version"] = v; });
ops.Add("p|profile=", delegate(string v) { options["profile"] = v; }); ops.Add("p|profile=", delegate(string v) { options["profile"] = v; });
ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; });
List<string> mainParams = ops.Parse(cmdparams); List<string> mainParams = ops.Parse(cmdparams);
@ -160,7 +161,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver
public void ArchiveRegion(Stream saveStream, Guid requestId) public void ArchiveRegion(Stream saveStream, Guid requestId)
{ {
new ArchiveWriteRequestPreparation(m_scene, saveStream, requestId).ArchiveRegion(new Dictionary<string, object>()); ArchiveRegion(saveStream, requestId, new Dictionary<string, object>());
}
public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options)
{
new ArchiveWriteRequestPreparation(m_scene, saveStream, requestId).ArchiveRegion(options);
} }
public void DearchiveRegion(string loadPath) public void DearchiveRegion(string loadPath)

View File

@ -211,6 +211,89 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
// TODO: Test presence of more files and contents of files. // TODO: Test presence of more files and contents of files.
} }
/// <summary>
/// Test saving an OpenSim Region Archive with the no assets option
/// </summary>
[Test]
public void TestSaveOarNoAssets()
{
TestHelper.InMethod();
// log4net.Config.XmlConfigurator.Configure();
SceneObjectPart part1 = CreateSceneObjectPart1();
SceneObjectGroup sog1 = new SceneObjectGroup(part1);
m_scene.AddNewSceneObject(sog1, false);
SceneObjectPart part2 = CreateSceneObjectPart2();
AssetNotecard nc = new AssetNotecard();
nc.BodyText = "Hello World!";
nc.Encode();
UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000");
UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000");
AssetBase ncAsset
= AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
m_scene.AssetService.Store(ncAsset);
SceneObjectGroup sog2 = new SceneObjectGroup(part2);
TaskInventoryItem ncItem
= new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
part2.Inventory.AddInventoryItem(ncItem, true);
m_scene.AddNewSceneObject(sog2, false);
MemoryStream archiveWriteStream = new MemoryStream();
Guid requestId = new Guid("00000000-0000-0000-0000-808080808080");
Dictionary<string, Object> options = new Dictionary<string, Object>();
options.Add("noassets", true);
m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options);
//AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer;
//while (assetServer.HasWaitingRequests())
// assetServer.ProcessNextRequest();
// Don't wait for completion - with --noassets save oar happens synchronously
// Monitor.Wait(this, 60000);
Assert.That(m_lastRequestId, Is.EqualTo(requestId));
byte[] archive = archiveWriteStream.ToArray();
MemoryStream archiveReadStream = new MemoryStream(archive);
TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
List<string> foundPaths = new List<string>();
List<string> expectedPaths = new List<string>();
expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog1));
expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2));
string filePath;
TarArchiveReader.TarEntryType tarEntryType;
byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
arr.LoadControlFile(filePath, data);
Assert.That(arr.ControlFileLoaded, Is.True);
while (tar.ReadEntry(out filePath, out tarEntryType) != null)
{
if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
{
Assert.Fail("Asset was found in saved oar of TestSaveOarNoAssets()");
}
else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
{
foundPaths.Add(filePath);
}
}
Assert.That(foundPaths, Is.EquivalentTo(expectedPaths));
// TODO: Test presence of more files and contents of files.
}
/// <summary> /// <summary>
/// Test loading an OpenSim Region Archive. /// Test loading an OpenSim Region Archive.
/// </summary> /// </summary>
@ -230,7 +313,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
// upset load // upset load
tar.WriteDir(ArchiveConstants.TERRAINS_PATH); tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
tar.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, ArchiveWriteRequestPreparation.CreateControlFile(new Dictionary<string, Object>())); tar.WriteFile(
ArchiveConstants.CONTROL_FILE_PATH,
new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>()));
SceneObjectPart part1 = CreateSceneObjectPart1(); SceneObjectPart part1 = CreateSceneObjectPart1();
SceneObjectGroup object1 = new SceneObjectGroup(part1); SceneObjectGroup object1 = new SceneObjectGroup(part1);
@ -331,7 +416,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
tar.WriteDir(ArchiveConstants.TERRAINS_PATH); tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
tar.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, ArchiveWriteRequestPreparation.CreateControlFile(new Dictionary<string, Object>())); tar.WriteFile(
ArchiveConstants.CONTROL_FILE_PATH,
new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>()));
RegionSettings rs = new RegionSettings(); RegionSettings rs = new RegionSettings();
rs.AgentLimit = 17; rs.AgentLimit = 17;

View File

@ -52,31 +52,44 @@ namespace OpenSim.Region.Framework.Interfaces
/// <summary> /// <summary>
/// Archive the region to the given path /// Archive the region to the given path
/// </summary> /// </summary>
/// /// <remarks>
/// This method occurs asynchronously. If you want notification of when it has completed then subscribe to /// This method occurs asynchronously. If you want notification of when it has completed then subscribe to
/// the EventManager.OnOarFileSaved event. /// the EventManager.OnOarFileSaved event.
/// /// </remarks>
/// <param name="savePath"></param> /// <param name="savePath"></param>
/// <param name="requestId">If supplied, this request Id is later returned in the saved event</param> /// <param name="requestId">If supplied, this request Id is later returned in the saved event</param>
/// <param name="options">Options for the save</param>
void ArchiveRegion(string savePath, Guid requestId, Dictionary<string, object> options); void ArchiveRegion(string savePath, Guid requestId, Dictionary<string, object> options);
/// <summary> /// <summary>
/// Archive the region to a stream. /// Archive the region to a stream.
/// </summary> /// </summary>
/// /// <remarks>
/// This method occurs asynchronously. If you want notification of when it has completed then subscribe to /// This method occurs asynchronously. If you want notification of when it has completed then subscribe to
/// the EventManager.OnOarFileSaved event. /// the EventManager.OnOarFileSaved event.
/// /// </remarks>
/// <param name="saveStream"></param> /// <param name="saveStream"></param>
/// <param name="requestId">If supplied, this request Id is later returned in the saved event</param> /// <param name="requestId">If supplied, this request Id is later returned in the saved event</param>
void ArchiveRegion(Stream saveStream, Guid requestId); void ArchiveRegion(Stream saveStream, Guid requestId);
/// <summary>
/// Archive the region to a stream.
/// </summary>
/// <remarks>
/// This method occurs asynchronously. If you want notification of when it has completed then subscribe to
/// the EventManager.OnOarFileSaved event.
/// </remarks>
/// <param name="saveStream"></param>
/// <param name="requestId">If supplied, this request Id is later returned in the saved event</param>
/// <param name="options">Options for the save</param>
void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options);
/// <summary> /// <summary>
/// Dearchive the given region archive. This replaces the existing scene. /// Dearchive the given region archive. This replaces the existing scene.
/// </summary> /// </summary>
/// /// <remarks>
/// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event. /// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event.
/// /// </remarks>
/// <param name="loadPath"></param> /// <param name="loadPath"></param>
void DearchiveRegion(string loadPath); void DearchiveRegion(string loadPath);

View File

@ -50,5 +50,7 @@ namespace OpenSim.Region.Framework.Interfaces
void ResumeScript(UUID itemID); void ResumeScript(UUID itemID);
ArrayList GetScriptErrors(UUID itemID); ArrayList GetScriptErrors(UUID itemID);
void SaveAllState();
} }
} }

View File

@ -111,6 +111,10 @@ namespace OpenSim.Region.Framework.Scenes
public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
public delegate void SceneShuttingDownDelegate(Scene scene);
public event SceneShuttingDownDelegate OnSceneShuttingDown;
/// <summary> /// <summary>
/// Fired when an object is touched/grabbed. /// Fired when an object is touched/grabbed.
/// </summary> /// </summary>
@ -2193,5 +2197,26 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
public void TriggerSceneShuttingDown(Scene s)
{
SceneShuttingDownDelegate handler = OnSceneShuttingDown;
if (handler != null)
{
foreach (SceneShuttingDownDelegate d in handler.GetInvocationList())
{
try
{
d(s);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerSceneShuttingDown failed - continuing. {0} {1}",
e.Message, e.StackTrace);
}
}
}
}
} }
} }

View File

@ -204,6 +204,7 @@ namespace OpenSim.Region.Framework.Scenes
private Timer m_mapGenerationTimer = new Timer(); private Timer m_mapGenerationTimer = new Timer();
private bool m_generateMaptiles; private bool m_generateMaptiles;
private bool m_useBackup = true;
// private Dictionary<UUID, string[]> m_UserNamesCache = new Dictionary<UUID, string[]>(); // private Dictionary<UUID, string[]> m_UserNamesCache = new Dictionary<UUID, string[]>();
@ -459,6 +460,11 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_sceneGraph; } get { return m_sceneGraph; }
} }
public bool UseBackup
{
get { return m_useBackup; }
}
// an instance to the physics plugin's Scene object. // an instance to the physics plugin's Scene object.
public PhysicsScene PhysicsScene public PhysicsScene PhysicsScene
{ {
@ -647,6 +653,9 @@ namespace OpenSim.Region.Framework.Scenes
IConfig startupConfig = m_config.Configs["Startup"]; IConfig startupConfig = m_config.Configs["Startup"];
m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance); m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance);
m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup);
if (!m_useBackup)
m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
//Animation states //Animation states
m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
@ -1064,6 +1073,8 @@ namespace OpenSim.Region.Framework.Scenes
shuttingdown = true; shuttingdown = true;
m_log.Debug("[SCENE]: Persisting changed objects"); m_log.Debug("[SCENE]: Persisting changed objects");
EventManager.TriggerSceneShuttingDown(this);
EntityBase[] entities = GetEntities(); EntityBase[] entities = GetEntities();
foreach (EntityBase entity in entities) foreach (EntityBase entity in entities)
{ {

View File

@ -1335,7 +1335,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
if (HasGroupChanged) if (m_scene.UseBackup && HasGroupChanged)
{ {
// don't backup while it's selected or you're asking for changes mid stream. // don't backup while it's selected or you're asking for changes mid stream.
if (isTimeToPersist() || forcedBackup) if (isTimeToPersist() || forcedBackup)

View File

@ -144,11 +144,10 @@ namespace OpenSim.Region.Framework.Scenes
public Vector3 StatusSandboxPos; public Vector3 StatusSandboxPos;
// TODO: This needs to be persisted in next XML version update! [XmlIgnore]
public int[] PayPrice = {-2,-2,-2,-2,-2};
public readonly int[] PayPrice = {-2,-2,-2,-2,-2};
[XmlIgnore]
public PhysicsActor PhysActor public PhysicsActor PhysActor
{ {
get { return m_physActor; } get { return m_physActor; }

View File

@ -341,6 +341,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl);
m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation);
m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem);
m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0);
m_SOPXmlProcessors.Add("PayPrice1", ProcessPayPrice1);
m_SOPXmlProcessors.Add("PayPrice2", ProcessPayPrice2);
m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3);
m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4);
#endregion #endregion
#region TaskInventoryXmlProcessors initialization #region TaskInventoryXmlProcessors initialization
@ -698,6 +703,32 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
{ {
obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty)); obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty));
} }
private static void ProcessPayPrice0(SceneObjectPart obj, XmlTextReader reader)
{
obj.PayPrice[0] = (int)reader.ReadElementContentAsInt("PayPrice0", String.Empty);
}
private static void ProcessPayPrice1(SceneObjectPart obj, XmlTextReader reader)
{
obj.PayPrice[1] = (int)reader.ReadElementContentAsInt("PayPrice1", String.Empty);
}
private static void ProcessPayPrice2(SceneObjectPart obj, XmlTextReader reader)
{
obj.PayPrice[2] = (int)reader.ReadElementContentAsInt("PayPrice2", String.Empty);
}
private static void ProcessPayPrice3(SceneObjectPart obj, XmlTextReader reader)
{
obj.PayPrice[3] = (int)reader.ReadElementContentAsInt("PayPrice3", String.Empty);
}
private static void ProcessPayPrice4(SceneObjectPart obj, XmlTextReader reader)
{
obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty);
}
#endregion #endregion
#region TaskInventoryXmlProcessors #region TaskInventoryXmlProcessors
@ -1069,7 +1100,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
shp.Media = PrimitiveBaseShape.MediaList.FromXml(value); shp.Media = PrimitiveBaseShape.MediaList.FromXml(value);
} }
#endregion #endregion
////////// Write ///////// ////////// Write /////////
@ -1175,6 +1205,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString());
WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); WriteBytes(writer, "TextureAnimation", sop.TextureAnimation);
WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); WriteBytes(writer, "ParticleSystem", sop.ParticleSystem);
writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString());
writer.WriteElementString("PayPrice1", sop.PayPrice[1].ToString());
writer.WriteElementString("PayPrice2", sop.PayPrice[2].ToString());
writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString());
writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString());
writer.WriteEndElement(); writer.WriteEndElement();
} }

View File

@ -95,7 +95,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
scene.AddCommand( scene.AddCommand(
this, "appearance show", this, "appearance show",
"appearance show", "appearance show",
"Show appearance information for each avatar in the simulator. At the moment, ", "Show appearance information for each avatar in the simulator.",
"At the moment this actually just checks that we have all the required baked textures. If not, then appearance is 'corrupt' and other avatars will continue to see a cloud.",
ShowAppearanceInfo); ShowAppearanceInfo);
} }

View File

@ -3316,12 +3316,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return m_ScriptEngine.GetStartParameter(m_itemID); return m_ScriptEngine.GetStartParameter(m_itemID);
} }
public void llGodLikeRezObject(string inventory, LSL_Vector pos)
{
m_host.AddScriptLPS(1);
NotImplemented("llGodLikeRezObject");
}
public void llRequestPermissions(string agent, int perm) public void llRequestPermissions(string agent, int perm)
{ {
UUID agentID = new UUID(); UUID agentID = new UUID();
@ -3870,9 +3864,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory)); throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
} }
// check if destination is an avatar // check if destination is an object
if (World.GetScenePresence(destId) != null) if (World.GetSceneObjectPart(destId) != null)
{ {
// destination is an object
World.MoveTaskInventoryItem(destId, m_host, objId);
}
else
{
ScenePresence presence = World.GetScenePresence(destId);
if (presence == null)
{
UserAccount account =
World.UserAccountService.GetUserAccount(
World.RegionInfo.ScopeID,
destId);
if (account == null)
{
llSay(0, "Can't find destination "+destId.ToString());
return;
}
}
// destination is an avatar // destination is an avatar
InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId); InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId);
@ -3893,16 +3907,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
m_host.AbsolutePosition.ToString(), m_host.AbsolutePosition.ToString(),
agentItem.ID, true, m_host.AbsolutePosition, agentItem.ID, true, m_host.AbsolutePosition,
bucket); bucket);
if (m_TransferModule != null) if (m_TransferModule != null)
m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
ScriptSleep(3000);
} }
else
{
// destination is an object
World.MoveTaskInventoryItem(destId, m_host, objId);
}
ScriptSleep(3000);
} }
public void llRemoveInventory(string name) public void llRemoveInventory(string name)
@ -4189,12 +4197,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
m_host.CollisionSoundVolume = (float)impact_volume; m_host.CollisionSoundVolume = (float)impact_volume;
} }
public void llCollisionSprite(string impact_sprite)
{
m_host.AddScriptLPS(1);
NotImplemented("llCollisionSprite");
}
public LSL_String llGetAnimation(string id) public LSL_String llGetAnimation(string id)
{ {
// This should only return a value if the avatar is in the same region // This should only return a value if the avatar is in the same region
@ -5526,12 +5528,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
ScriptSleep(100); ScriptSleep(100);
} }
public void llSetSoundQueueing(int queue)
{
m_host.AddScriptLPS(1);
NotImplemented("llSetSoundQueueing");
}
public void llSetSoundRadius(double radius) public void llSetSoundRadius(double radius)
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
@ -10312,6 +10308,73 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return rq.ToString(); return rq.ToString();
} }
#region Not Implemented
//
// Listing the unimplemented lsl functions here, please move
// them from this region as they are completed
//
public void llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
{
m_host.AddScriptLPS(1);
NotImplemented("llCastRay");
}
public void llGetEnv(LSL_String name)
{
m_host.AddScriptLPS(1);
NotImplemented("llGetEnv");
}
public void llGetSPMaxMemory()
{
m_host.AddScriptLPS(1);
NotImplemented("llGetSPMaxMemory");
}
public void llGetUsedMemory()
{
m_host.AddScriptLPS(1);
NotImplemented("llGetUsedMemory");
}
public void llRegionSayTo( LSL_Key target, LSL_Integer channel, LSL_String msg )
{
m_host.AddScriptLPS(1);
NotImplemented("llRegionSayTo");
}
public void llScriptProfiler( LSL_Integer flags )
{
m_host.AddScriptLPS(1);
NotImplemented("llScriptProfiler");
}
public void llSetSoundQueueing(int queue)
{
m_host.AddScriptLPS(1);
NotImplemented("llSetSoundQueueing");
}
public void llCollisionSprite(string impact_sprite)
{
m_host.AddScriptLPS(1);
NotImplemented("llCollisionSprite");
}
public void llGodLikeRezObject(string inventory, LSL_Vector pos)
{
m_host.AddScriptLPS(1);
NotImplemented("llGodLikeRezObject");
}
#endregion
} }
public class NotecardCache public class NotecardCache

View File

@ -393,11 +393,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
return 0; return 0;
} }
public object DoMaintenance(object p) public void SaveAllState()
{ {
object[] parms = (object[])p;
int sleepTime = (int)parms[0];
foreach (IScriptInstance inst in m_Scripts.Values) foreach (IScriptInstance inst in m_Scripts.Values)
{ {
if (inst.EventTime() > m_EventLimit) if (inst.EventTime() > m_EventLimit)
@ -407,6 +404,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
inst.Start(); inst.Start();
} }
} }
}
public object DoMaintenance(object p)
{
object[] parms = (object[])p;
int sleepTime = (int)parms[0];
SaveAllState();
System.Threading.Thread.Sleep(sleepTime); System.Threading.Thread.Sleep(sleepTime);

View File

@ -40,9 +40,9 @@ namespace OpenSim.Services.InventoryService
{ {
public class XInventoryService : ServiceBase, IInventoryService public class XInventoryService : ServiceBase, IInventoryService
{ {
private static readonly ILog m_log = // private static readonly ILog m_log =
LogManager.GetLogger( // LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType); // MethodBase.GetCurrentMethod().DeclaringType);
protected IXInventoryData m_Database; protected IXInventoryData m_Database;
protected bool m_AllowDelete = true; protected bool m_AllowDelete = true;
@ -424,7 +424,7 @@ namespace OpenSim.Services.InventoryService
{ {
if (!m_Database.DeleteItems( if (!m_Database.DeleteItems(
new string[] { "inventoryID", "assetType" }, new string[] { "inventoryID", "assetType" },
new string[] { id.ToString(), ((sbyte)AssetType.Link).ToString() })); new string[] { id.ToString(), ((sbyte)AssetType.Link).ToString() }))
{ {
m_Database.DeleteItems( m_Database.DeleteItems(
new string[] { "inventoryID", "assetType" }, new string[] { "inventoryID", "assetType" },