diff --git a/OpenSim/Region/Environment/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Environment/Scenes/AsyncSceneObjectGroupDeleter.cs
new file mode 100644
index 0000000000..8c43bcb9b4
--- /dev/null
+++ b/OpenSim/Region/Environment/Scenes/AsyncSceneObjectGroupDeleter.cs
@@ -0,0 +1,146 @@
+/*
+ * 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 OpenSim 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.Reflection;
+using System.Timers;
+using log4net;
+using OpenMetaverse;
+using OpenMetaverse.Packets;
+using OpenSim.Framework;
+
+namespace OpenSim.Region.Environment.Scenes
+{
+ class DeleteToInventoryHolder
+ {
+ public DeRezObjectPacket DeRezPacket;
+ public EntityBase selectedEnt;
+ public IClientAPI remoteClient;
+ public SceneObjectGroup objectGroup;
+ public UUID folderID;
+ public bool permissionToDelete;
+ }
+
+ ///
+ /// Asynchronously derez objects. This is used to derez large number of objects to inventory without holding
+ /// up the main client thread.
+ ///
+ public class AsyncSceneObjectGroupDeleter
+ {
+ private static readonly ILog m_log
+ = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private Timer m_inventoryTicker;
+ private readonly Queue m_inventoryDeletes = new Queue();
+ private Scene m_scene;
+
+ public AsyncSceneObjectGroupDeleter(Scene scene)
+ {
+ m_scene = scene;
+ }
+
+ ///
+ /// Delete the given object from the scene
+ ///
+ public void DeleteToInventory(
+ DeRezObjectPacket DeRezPacket, UUID folderID, SceneObjectGroup objectGroup, IClientAPI remoteClient,
+ EntityBase selectedEnt, bool permissionToDelete)
+ {
+ if (m_inventoryTicker != null)
+ {
+ m_inventoryTicker.Stop();
+ }
+ else
+ {
+ m_inventoryTicker = new Timer(2000);
+ m_inventoryTicker.AutoReset = false;
+ m_inventoryTicker.Elapsed += InventoryRunDeleteTimer;
+ }
+
+ lock (m_inventoryDeletes)
+ {
+ DeleteToInventoryHolder dtis = new DeleteToInventoryHolder();
+ dtis.DeRezPacket = DeRezPacket;
+ dtis.folderID = folderID;
+ dtis.objectGroup = objectGroup;
+ dtis.remoteClient = remoteClient;
+ dtis.selectedEnt = selectedEnt;
+ dtis.permissionToDelete = permissionToDelete;
+
+ m_inventoryDeletes.Enqueue(dtis);
+ }
+
+ m_inventoryTicker.Start();
+
+ // Visually remove it, even if it isnt really gone yet.
+ if (permissionToDelete)
+ objectGroup.FakeDeleteGroup();
+ }
+
+ private void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e)
+ {
+ m_log.Info("Starting inventory send loop");
+ while (InventoryDeQueueAndDelete() == true)
+ {
+ m_log.Info("Returned item successfully, continuing...");
+ }
+ }
+
+ private bool InventoryDeQueueAndDelete()
+ {
+ DeleteToInventoryHolder x = null;
+
+ try
+ {
+ lock (m_inventoryDeletes)
+ {
+ int left = m_inventoryDeletes.Count;
+ if (left > 0)
+ {
+ m_log.InfoFormat("Sending deleted object to user's inventory, {0} item(s) remaining.", left);
+ x = m_inventoryDeletes.Dequeue();
+ m_scene.DeleteToInventory(
+ x.DeRezPacket, x.selectedEnt, x.remoteClient, x.objectGroup, x.folderID, x.permissionToDelete);
+ return true;
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ // We can't put the object group details in here since the root part may have disappeared (which is where these sit).
+ // FIXME: This needs to be fixed.
+ m_log.ErrorFormat(
+ "[AGENT INVENTORY]: Queued deletion of scene object to agent {0} {1} failed: {2}",
+ (x != null ? x.remoteClient.Name : "unavailable"), (x != null ? x.remoteClient.AgentId.ToString() : "unavailable"), e.ToString());
+ }
+
+ m_log.Info("No objects left in inventory delete queue.");
+ return false;
+ }
+ }
+}
diff --git a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
index 5ff6dec038..8557b1c5b2 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
@@ -40,23 +40,15 @@ using OpenSim.Region.Environment.Interfaces;
namespace OpenSim.Region.Environment.Scenes
{
- class DeleteToInventoryHolder
- {
- public DeRezObjectPacket DeRezPacket;
- public EntityBase selectedEnt;
- public IClientAPI remoteClient;
- public SceneObjectGroup objectGroup;
- public UUID folderID;
- public bool permissionToDelete;
- }
-
public partial class Scene
{
- private Timer m_inventoryTicker;
- private readonly Queue m_inventoryDeletes = new Queue();
-
private static readonly ILog m_log
= LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Allows asynchronous derezzing of objects from the scene into a client's inventory.
+ ///
+ private AsyncSceneObjectGroupDeleter m_asyncSceneObjectDeleter;
///
/// Start all the scripts in the scene which should be started.
@@ -1546,35 +1538,8 @@ namespace OpenSim.Region.Environment.Scenes
if (permissionToTake)
{
- if (m_inventoryTicker != null)
- {
- m_inventoryTicker.Stop();
- }
- else
- {
- m_inventoryTicker = new Timer(2000);
- m_inventoryTicker.AutoReset = false;
- m_inventoryTicker.Elapsed += InventoryRunDeleteTimer;
- }
-
- lock (m_inventoryDeletes)
- {
- DeleteToInventoryHolder dtis = new DeleteToInventoryHolder();
- dtis.DeRezPacket = DeRezPacket;
- dtis.folderID = folderID;
- dtis.objectGroup = objectGroup;
- dtis.remoteClient = remoteClient;
- dtis.selectedEnt = selectedEnt;
- dtis.permissionToDelete = permissionToDelete;
-
- m_inventoryDeletes.Enqueue(dtis);
- }
-
- m_inventoryTicker.Start();
-
- // Visually remove it, even if it isnt really gone yet.
- if (permissionToDelete)
- objectGroup.FakeDeleteGroup();
+ m_asyncSceneObjectDeleter.DeleteToInventory(
+ DeRezPacket, folderID, objectGroup, remoteClient, selectedEnt, permissionToDelete);
}
else if (permissionToDelete)
{
@@ -1584,47 +1549,17 @@ namespace OpenSim.Region.Environment.Scenes
}
}
- void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e)
- {
- m_log.Info("Starting inventory send loop");
- while (InventoryDeQueueAndDelete() == true)
- {
- m_log.Info("Returned item successfully, continuing...");
- }
- }
-
- private bool InventoryDeQueueAndDelete()
- {
- DeleteToInventoryHolder x = null;
-
- try
- {
- lock (m_inventoryDeletes)
- {
- int left = m_inventoryDeletes.Count;
- if (left > 0)
- {
- m_log.InfoFormat("Sending deleted object to user's inventory, {0} item(s) remaining.", left);
- x = m_inventoryDeletes.Dequeue();
- DeleteToInventory(x.DeRezPacket, x.selectedEnt, x.remoteClient, x.objectGroup, x.folderID, x.permissionToDelete);
- return true;
- }
- }
- }
- catch(Exception e)
- {
- // We can't put the object group details in here since the root part may have disappeared (which is where these sit).
- // FIXME: This needs to be fixed.
- m_log.ErrorFormat(
- "[AGENT INVENTORY]: Queued deletion of scene object to agent {0} {1} failed: {2}",
- (x != null ? x.remoteClient.Name : "unavailable"), (x != null ? x.remoteClient.AgentId.ToString() : "unavailable"), e.ToString());
- }
-
- m_log.Info("No objects left in inventory delete queue.");
- return false;
- }
-
- private void DeleteToInventory(DeRezObjectPacket DeRezPacket, EntityBase selectedEnt, IClientAPI remoteClient, SceneObjectGroup objectGroup, UUID folderID, bool permissionToDelete)
+ ///
+ /// Delete a scene object from a scene and place in the given avatar's inventory.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void DeleteToInventory(DeRezObjectPacket DeRezPacket, EntityBase selectedEnt, IClientAPI remoteClient,
+ SceneObjectGroup objectGroup, UUID folderID, bool permissionToDelete)
{
string sceneObjectXml = objectGroup.ToXmlString();
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs
index 42e9c02a2b..88da9be279 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.cs
@@ -275,6 +275,7 @@ namespace OpenSim.Region.Environment.Scenes
m_eventManager = new EventManager();
m_externalChecks = new SceneExternalChecks(this);
+ m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
// Load region settings
m_regInfo.RegionSettings = m_storageManager.DataStore.LoadRegionSettings(m_regInfo.RegionID);