Merge branch 'careminster-presence-refactor' of ssh://3dhosting.de/var/git/careminster into careminster-presence-refactor

This commit is contained in:
meta7
2010-08-30 11:42:17 -07:00
81 changed files with 3201 additions and 2665 deletions

View File

@@ -427,7 +427,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
{
if (!m_scene.Permissions.CanRezObject(
part.ParentGroup.Children.Count, remoteClient.AgentId, presence.AbsolutePosition))
part.ParentGroup.PrimCount, remoteClient.AgentId, presence.AbsolutePosition))
return;
presence.Appearance.DetachAttachment(itemID);
@@ -471,12 +471,86 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
SceneObjectSerializer.ToOriginalXmlFormat(group);
group.DetachToInventoryPrep();
m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
m_scene.UpdateKnownItem(remoteClient, group,group.GetFromItemID(), group.OwnerID);
UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID);
m_scene.DeleteSceneObject(group, false);
return;
}
}
}
}
public void UpdateAttachmentPosition(IClientAPI client, SceneObjectGroup sog, Vector3 pos)
{
// If this is an attachment, then we need to save the modified
// object back into the avatar's inventory. First we save the
// attachment point information, then we update the relative
// positioning (which caused this method to get driven in the
// first place. Then we have to mark the object as NOT an
// attachment. This is necessary in order to correctly save
// and retrieve GroupPosition information for the attachment.
// Then we save the asset back into the appropriate inventory
// entry. Finally, we restore the object's attachment status.
byte attachmentPoint = sog.GetAttachmentPoint();
sog.UpdateGroupPosition(pos);
sog.RootPart.IsAttachment = false;
sog.AbsolutePosition = sog.RootPart.AttachedPos;
UpdateKnownItem(client, sog, sog.GetFromItemID(), sog.OwnerID);
sog.SetAttachmentPoint(attachmentPoint);
}
/// <summary>
/// Update the attachment asset for the new sog details if they have changed.
/// </summary>
///
/// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects,
/// these details are not stored on the region.
///
/// <param name="remoteClient"></param>
/// <param name="grp"></param>
/// <param name="itemID"></param>
/// <param name="agentID"></param>
protected void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID)
{
if (grp != null)
{
if (!grp.HasGroupChanged)
{
m_log.WarnFormat("[ATTACHMENTS MODULE]: Save request for {0} which is unchanged", grp.UUID);
return;
}
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
grp.UUID, grp.GetAttachmentPoint());
string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
item = m_scene.InventoryService.GetItem(item);
if (item != null)
{
AssetBase asset = m_scene.CreateAsset(
grp.GetPartName(grp.LocalId),
grp.GetPartDescription(grp.LocalId),
(sbyte)AssetType.Object,
Utils.StringToBytes(sceneObjectXml),
remoteClient.AgentId);
m_scene.AssetService.Store(asset);
item.AssetID = asset.FullID;
item.Description = asset.Description;
item.Name = asset.Name;
item.AssetType = asset.Type;
item.InvType = (int)InventoryType.Object;
m_scene.InventoryService.UpdateItem(item);
// this gets called when the agent logs off!
if (remoteClient != null)
remoteClient.SendInventoryItemCreateUpdate(item, 0);
}
}
}
}
}
}

View File

@@ -223,4 +223,4 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
OnInstantMessage(null, msg);
}
}
}
}

View File

@@ -132,8 +132,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
{
UUID toAgentID = new UUID(im.toAgentID);
//m_log.DebugFormat("[INSTANT MESSAGE]: Attempting delivery of IM from {0} to {1}", im.fromAgentName, toAgentID.ToString());
// Try root avatar only first
foreach (Scene scene in m_Scenes)
{
@@ -176,6 +174,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
}
}
m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
SendGridInstantMessageViaXMLRPC(im, result);
return;

View File

@@ -261,7 +261,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
while (archivePath.Length > 0)
{
m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
// m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
if (resolvedFolders.ContainsKey(archivePath))
{

View File

@@ -41,7 +41,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
/// </summary>
public static class InventoryArchiveUtils
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// Character used for escaping the path delimter ("\/") and itself ("\\") in human escaped strings
public static readonly char ESCAPE_CHARACTER = '\\';
@@ -120,6 +120,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
foundFolders.Add(startFolder);
return foundFolders;
}
// If the path isn't just / then trim any starting extraneous slashes
path = path.TrimStart(new char[] { PATH_DELIMITER });
// m_log.DebugFormat("[INVENTORY ARCHIVE UTILS]: Adjusted path in FindFolderByPath() is [{0}]", path);
string[] components = SplitEscapedPath(path);
components[0] = UnescapePath(components[0]);
@@ -199,6 +204,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
public static InventoryItemBase FindItemByPath(
IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
{
// If the path isn't just / then trim any starting extraneous slashes
path = path.TrimStart(new char[] { PATH_DELIMITER });
string[] components = SplitEscapedPath(path);
components[0] = UnescapePath(components[0]);

View File

@@ -221,7 +221,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
InventoryItemBase inventoryItem = null;
InventoryFolderBase rootFolder = m_scene.InventoryService.GetRootFolder(m_userInfo.PrincipalID);
bool foundStar = false;
bool saveFolderContentsOnly = false;
// Eliminate double slashes and any leading / on the path.
string[] components
@@ -234,7 +234,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
// folder itself. This may get more sophisicated later on
if (maxComponentIndex >= 0 && components[maxComponentIndex] == STAR_WILDCARD)
{
foundStar = true;
saveFolderContentsOnly = true;
maxComponentIndex--;
}
@@ -281,10 +281,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
{
m_log.DebugFormat(
"[INVENTORY ARCHIVER]: Found folder {0} {1} at {2}",
inventoryFolder.Name, inventoryFolder.ID, m_invPath);
inventoryFolder.Name,
inventoryFolder.ID,
m_invPath == String.Empty ? InventoryFolderImpl.PATH_DELIMITER : m_invPath );
//recurse through all dirs getting dirs and files
SaveInvFolder(inventoryFolder, ArchiveConstants.INVENTORY_PATH, !foundStar);
SaveInvFolder(inventoryFolder, ArchiveConstants.INVENTORY_PATH, !saveFolderContentsOnly);
}
else if (inventoryItem != null)
{

View File

@@ -55,12 +55,58 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
{
protected ManualResetEvent mre = new ManualResetEvent(false);
/// <summary>
/// Stream of data representing a common IAR that can be reused in load tests.
/// </summary>
protected MemoryStream m_iarStream;
protected UserAccount m_ua1
= new UserAccount {
PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000555"),
FirstName = "Mr",
LastName = "Tiddles" };
protected UserAccount m_ua2
= new UserAccount {
PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000666"),
FirstName = "Lord",
LastName = "Lucan" };
string m_item1Name = "b.lsl";
private void SaveCompleted(
Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
Exception reportedException)
{
mre.Set();
}
[SetUp]
public void Init()
{
ConstructDefaultIarForTestLoad();
}
protected void ConstructDefaultIarForTestLoad()
{
string archiveItemName = InventoryArchiveWriteRequest.CreateArchiveItemName(m_item1Name, UUID.Random());
MemoryStream archiveWriteStream = new MemoryStream();
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
InventoryItemBase item1 = new InventoryItemBase();
item1.Name = m_item1Name;
item1.AssetID = UUID.Random();
item1.GroupID = UUID.Random();
item1.CreatorId = OspResolver.MakeOspa(m_ua2.FirstName, m_ua2.LastName);
//item1.CreatorId = userUuid.ToString();
//item1.CreatorId = "00000000-0000-0000-0000-000000000444";
item1.Owner = UUID.Zero;
string item1FileName
= string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, archiveItemName);
tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1));
tar.Close();
m_iarStream = new MemoryStream(archiveWriteStream.ToArray());
}
/// <summary>
/// Test saving an inventory path to a V0.1 OpenSim Inventory Archive
@@ -122,6 +168,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
MemoryStream archiveWriteStream = new MemoryStream();
archiverModule.OnInventoryArchiveSaved += SaveCompleted;
// Test saving a particular path
mre.Reset();
archiverModule.ArchiveInventory(
Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream);
@@ -148,7 +195,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
while (tar.ReadEntry(out filePath, out tarEntryType) != null)
{
Console.WriteLine("Got {0}", filePath);
// Console.WriteLine("Got {0}", filePath);
// if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
// {
@@ -296,6 +343,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
// TODO: Test presence of more files and contents of files.
}
/// <summary>
/// Test that things work when the load path specified starts with a slash
/// </summary>
[Test]
public void TestLoadIarPathStartsWithSlash()
{
TestHelper.InMethod();
// log4net.Config.XmlConfigurator.Configure();
SerialiserModule serialiserModule = new SerialiserModule();
InventoryArchiverModule archiverModule = new InventoryArchiverModule(true);
Scene scene = SceneSetupHelpers.SetupScene("inventory");
SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
UserProfileTestUtils.CreateUserWithInventory(scene, m_ua1, "password");
archiverModule.DearchiveInventory(m_ua1.FirstName, m_ua1.LastName, "/Objects", "password", m_iarStream);
InventoryItemBase foundItem1
= InventoryArchiveUtils.FindItemByPath(
scene.InventoryService, m_ua1.PrincipalID, "/Objects/" + m_item1Name);
Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1 in TestLoadIarFolderStartsWithSlash()");
}
/// <summary>
/// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
/// an account exists with the creator name.
@@ -308,34 +379,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
TestHelper.InMethod();
//log4net.Config.XmlConfigurator.Configure();
string userFirstName = "Mr";
string userLastName = "Tiddles";
UUID userUuid = UUID.Parse("00000000-0000-0000-0000-000000000555");
string userItemCreatorFirstName = "Lord";
string userItemCreatorLastName = "Lucan";
UUID userItemCreatorUuid = UUID.Parse("00000000-0000-0000-0000-000000000666");
string item1Name = "b.lsl";
string archiveItemName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1Name, UUID.Random());
MemoryStream archiveWriteStream = new MemoryStream();
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
InventoryItemBase item1 = new InventoryItemBase();
item1.Name = item1Name;
item1.AssetID = UUID.Random();
item1.GroupID = UUID.Random();
item1.CreatorId = OspResolver.MakeOspa(userItemCreatorFirstName, userItemCreatorLastName);
//item1.CreatorId = userUuid.ToString();
//item1.CreatorId = "00000000-0000-0000-0000-000000000444";
item1.Owner = UUID.Zero;
string item1FileName
= string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, archiveItemName);
tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1));
tar.Close();
MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
SerialiserModule serialiserModule = new SerialiserModule();
InventoryArchiverModule archiverModule = new InventoryArchiverModule(true);
@@ -344,15 +387,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
UserProfileTestUtils.CreateUserWithInventory(
scene, userFirstName, userLastName, userUuid, "meowfood");
UserProfileTestUtils.CreateUserWithInventory(
scene, userItemCreatorFirstName, userItemCreatorLastName, userItemCreatorUuid, "hampshire");
UserProfileTestUtils.CreateUserWithInventory(scene, m_ua1, "meowfood");
UserProfileTestUtils.CreateUserWithInventory(scene, m_ua2, "hampshire");
archiverModule.DearchiveInventory(userFirstName, userLastName, "/", "meowfood", archiveReadStream);
archiverModule.DearchiveInventory(m_ua1.FirstName, m_ua1.LastName, "/", "meowfood", m_iarStream);
InventoryItemBase foundItem1
= InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userUuid, item1Name);
= InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_ua1.PrincipalID, m_item1Name);
Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
@@ -362,31 +403,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
// foundItem1.CreatorId, Is.EqualTo(item1.CreatorId),
// "Loaded item non-uuid creator doesn't match original");
Assert.That(
foundItem1.CreatorId, Is.EqualTo(userItemCreatorUuid.ToString()),
foundItem1.CreatorId, Is.EqualTo(m_ua2.PrincipalID.ToString()),
"Loaded item non-uuid creator doesn't match original");
Assert.That(
foundItem1.CreatorIdAsUuid, Is.EqualTo(userItemCreatorUuid),
foundItem1.CreatorIdAsUuid, Is.EqualTo(m_ua2.PrincipalID),
"Loaded item uuid creator doesn't match original");
Assert.That(foundItem1.Owner, Is.EqualTo(userUuid),
Assert.That(foundItem1.Owner, Is.EqualTo(m_ua1.PrincipalID),
"Loaded item owner doesn't match inventory reciever");
// Now try loading to a root child folder
UserInventoryTestUtils.CreateInventoryFolder(scene.InventoryService, userUuid, "xA");
archiveReadStream = new MemoryStream(archiveReadStream.ToArray());
archiverModule.DearchiveInventory(userFirstName, userLastName, "xA", "meowfood", archiveReadStream);
UserInventoryTestUtils.CreateInventoryFolder(scene.InventoryService, m_ua1.PrincipalID, "xA");
MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray());
archiverModule.DearchiveInventory(m_ua1.FirstName, m_ua1.LastName, "xA", "meowfood", archiveReadStream);
InventoryItemBase foundItem2
= InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userUuid, "xA/" + item1Name);
= InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_ua1.PrincipalID, "xA/" + m_item1Name);
Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2");
// Now try loading to a more deeply nested folder
UserInventoryTestUtils.CreateInventoryFolder(scene.InventoryService, userUuid, "xB/xC");
UserInventoryTestUtils.CreateInventoryFolder(scene.InventoryService, m_ua1.PrincipalID, "xB/xC");
archiveReadStream = new MemoryStream(archiveReadStream.ToArray());
archiverModule.DearchiveInventory(userFirstName, userLastName, "xB/xC", "meowfood", archiveReadStream);
archiverModule.DearchiveInventory(m_ua1.FirstName, m_ua1.LastName, "xB/xC", "meowfood", archiveReadStream);
InventoryItemBase foundItem3
= InventoryArchiveUtils.FindItemByPath(scene.InventoryService, userUuid, "xB/xC/" + item1Name);
= InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_ua1.PrincipalID, "xB/xC/" + m_item1Name);
Assert.That(foundItem3, Is.Not.Null, "Didn't find loaded item 3");
}

View File

@@ -32,7 +32,6 @@ using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
@@ -92,7 +91,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
m_TransferModule = m_Scenelist[0].RequestModuleInterface<IMessageTransferModule>();
if (m_TransferModule == null)
{
m_log.Error("[INVENTORY TRANSFER] No Message transfer module found, transfers will be local only");
m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
m_Enabled = false;
m_Scenelist.Clear();
@@ -185,7 +184,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
{
UUID folderID = new UUID(im.binaryBucket, 1);
m_log.DebugFormat("[AGENT INVENTORY]: Inserting original folder {0} "+
m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+
"into agent {1}'s inventory",
folderID, new UUID(im.toAgentID));
@@ -221,7 +220,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
UUID itemID = new UUID(im.binaryBucket, 1);
m_log.DebugFormat("[AGENT INVENTORY]: (giving) Inserting item {0} "+
m_log.DebugFormat("[INVENTORY TRANSFER]: (giving) Inserting item {0} "+
"into agent {1}'s inventory",
itemID, new UUID(im.toAgentID));
@@ -288,10 +287,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
// inventory is loaded. Courtesy of the above bulk update,
// It will have been pushed to the client, too
//
//CachedUserInfo userInfo =
// scene.CommsManager.UserProfileCacheService.
// GetUserDetails(client.AgentId);
IInventoryService invService = scene.InventoryService;
InventoryFolderBase trashFolder =

View File

@@ -200,6 +200,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final destination is x={0} y={1} uuid={2}",
finalDestination.RegionLocX / Constants.RegionSize, finalDestination.RegionLocY / Constants.RegionSize, finalDestination.RegionID);
// Check that these are not the same coordinates
if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX &&
finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY)
{
// Can't do. Viewer crashes
sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again.");
return;
}
//
// This is it
//
@@ -446,6 +455,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Now let's make it officially a child agent
sp.MakeChildAgent();
sp.Scene.CleanDroppedAttachments();
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
if (NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg))

View File

@@ -34,6 +34,7 @@ using System.Threading;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Messages.Linden;
using OpenMetaverse.Packets;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
@@ -137,10 +138,11 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
{
if (!queues.ContainsKey(agentId))
{
/*
m_log.DebugFormat(
"[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
agentId, m_scene.RegionInfo.RegionName);
*/
queues[agentId] = new Queue<OSD>();
}
@@ -200,7 +202,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
private void ClientClosed(UUID AgentID, Scene scene)
{
m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName);
//m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName);
int count = 0;
while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5)
@@ -284,7 +286,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
// Reuse open queues. The client does!
if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
{
m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
//m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
EventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
}
else
@@ -365,7 +367,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
{
// Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
array.Add(EventQueueHelper.KeepAliveEvent());
m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
//m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
}
else
{
@@ -394,8 +396,8 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
responsedata["keepalive"] = false;
responsedata["reusecontext"] = false;
responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
//m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
return responsedata;
//m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
}
public Hashtable NoEvents(UUID requestID, UUID agentID)
@@ -461,7 +463,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
{
// Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
array.Add(EventQueueHelper.KeepAliveEvent());
m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
//m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
}
else
{
@@ -697,9 +699,9 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
//m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
}
public void ParcelProperties(ParcelPropertiesPacket parcelPropertiesPacket, UUID avatarID)
public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
{
OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesPacket);
OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage);
Enqueue(item, avatarID);
}

View File

@@ -30,6 +30,7 @@ using System.Net;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Messages.Linden;
namespace OpenSim.Region.CoreModules.Framework.EventQueue
{
@@ -309,116 +310,6 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
return chatterBoxSessionAgentListUpdates;
}
public static OSD ParcelProperties(ParcelPropertiesPacket parcelPropertiesPacket)
{
OSDMap parcelProperties = new OSDMap();
OSDMap body = new OSDMap();
OSDArray ageVerificationBlock = new OSDArray();
OSDMap ageVerificationMap = new OSDMap();
ageVerificationMap.Add("RegionDenyAgeUnverified",
OSD.FromBoolean(parcelPropertiesPacket.AgeVerificationBlock.RegionDenyAgeUnverified));
ageVerificationBlock.Add(ageVerificationMap);
body.Add("AgeVerificationBlock", ageVerificationBlock);
// LL sims send media info in this event queue message but it's not in the UDP
// packet we construct this event queue message from. This should be refactored in
// other areas of the code so it can all be send in the same message. Until then we will
// still send the media info via UDP
//OSDArray mediaData = new OSDArray();
//OSDMap mediaDataMap = new OSDMap();
//mediaDataMap.Add("MediaDesc", OSD.FromString(""));
//mediaDataMap.Add("MediaHeight", OSD.FromInteger(0));
//mediaDataMap.Add("MediaLoop", OSD.FromInteger(0));
//mediaDataMap.Add("MediaType", OSD.FromString("type/type"));
//mediaDataMap.Add("MediaWidth", OSD.FromInteger(0));
//mediaDataMap.Add("ObscureMedia", OSD.FromInteger(0));
//mediaDataMap.Add("ObscureMusic", OSD.FromInteger(0));
//mediaData.Add(mediaDataMap);
//body.Add("MediaData", mediaData);
OSDArray parcelData = new OSDArray();
OSDMap parcelDataMap = new OSDMap();
OSDArray AABBMax = new OSDArray(3);
AABBMax.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.AABBMax.X));
AABBMax.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.AABBMax.Y));
AABBMax.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.AABBMax.Z));
parcelDataMap.Add("AABBMax", AABBMax);
OSDArray AABBMin = new OSDArray(3);
AABBMin.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.AABBMin.X));
AABBMin.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.AABBMin.Y));
AABBMin.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.AABBMin.Z));
parcelDataMap.Add("AABBMin", AABBMin);
parcelDataMap.Add("Area", OSD.FromInteger(parcelPropertiesPacket.ParcelData.Area));
parcelDataMap.Add("AuctionID", OSD.FromBinary(uintToByteArray(parcelPropertiesPacket.ParcelData.AuctionID)));
parcelDataMap.Add("AuthBuyerID", OSD.FromUUID(parcelPropertiesPacket.ParcelData.AuthBuyerID));
parcelDataMap.Add("Bitmap", OSD.FromBinary(parcelPropertiesPacket.ParcelData.Bitmap));
parcelDataMap.Add("Category", OSD.FromInteger((int)parcelPropertiesPacket.ParcelData.Category));
parcelDataMap.Add("ClaimDate", OSD.FromInteger(parcelPropertiesPacket.ParcelData.ClaimDate));
parcelDataMap.Add("ClaimPrice", OSD.FromInteger(parcelPropertiesPacket.ParcelData.ClaimPrice));
parcelDataMap.Add("Desc", OSD.FromString(Utils.BytesToString(parcelPropertiesPacket.ParcelData.Desc)));
parcelDataMap.Add("GroupID", OSD.FromUUID(parcelPropertiesPacket.ParcelData.GroupID));
parcelDataMap.Add("GroupPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.GroupPrims));
parcelDataMap.Add("IsGroupOwned", OSD.FromBoolean(parcelPropertiesPacket.ParcelData.IsGroupOwned));
parcelDataMap.Add("LandingType", OSD.FromInteger(parcelPropertiesPacket.ParcelData.LandingType));
parcelDataMap.Add("LocalID", OSD.FromInteger(parcelPropertiesPacket.ParcelData.LocalID));
parcelDataMap.Add("MaxPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.MaxPrims));
parcelDataMap.Add("MediaAutoScale", OSD.FromInteger((int)parcelPropertiesPacket.ParcelData.MediaAutoScale));
parcelDataMap.Add("MediaID", OSD.FromUUID(parcelPropertiesPacket.ParcelData.MediaID));
parcelDataMap.Add("MediaURL", OSD.FromString(Utils.BytesToString(parcelPropertiesPacket.ParcelData.MediaURL)));
parcelDataMap.Add("MusicURL", OSD.FromString(Utils.BytesToString(parcelPropertiesPacket.ParcelData.MusicURL)));
parcelDataMap.Add("Name", OSD.FromString(Utils.BytesToString(parcelPropertiesPacket.ParcelData.Name)));
parcelDataMap.Add("OtherCleanTime", OSD.FromInteger(parcelPropertiesPacket.ParcelData.OtherCleanTime));
parcelDataMap.Add("OtherCount", OSD.FromInteger(parcelPropertiesPacket.ParcelData.OtherCount));
parcelDataMap.Add("OtherPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.OtherPrims));
parcelDataMap.Add("OwnerID", OSD.FromUUID(parcelPropertiesPacket.ParcelData.OwnerID));
parcelDataMap.Add("OwnerPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.OwnerPrims));
parcelDataMap.Add("ParcelFlags", OSD.FromBinary(uintToByteArray(parcelPropertiesPacket.ParcelData.ParcelFlags)));
parcelDataMap.Add("ParcelPrimBonus", OSD.FromReal(parcelPropertiesPacket.ParcelData.ParcelPrimBonus));
parcelDataMap.Add("PassHours", OSD.FromReal(parcelPropertiesPacket.ParcelData.PassHours));
parcelDataMap.Add("PassPrice", OSD.FromInteger(parcelPropertiesPacket.ParcelData.PassPrice));
parcelDataMap.Add("PublicCount", OSD.FromInteger(parcelPropertiesPacket.ParcelData.PublicCount));
parcelDataMap.Add("RegionDenyAnonymous", OSD.FromBoolean(parcelPropertiesPacket.ParcelData.RegionDenyAnonymous));
parcelDataMap.Add("RegionDenyIdentified", OSD.FromBoolean(parcelPropertiesPacket.ParcelData.RegionDenyIdentified));
parcelDataMap.Add("RegionDenyTransacted", OSD.FromBoolean(parcelPropertiesPacket.ParcelData.RegionDenyTransacted));
parcelDataMap.Add("RegionPushOverride", OSD.FromBoolean(parcelPropertiesPacket.ParcelData.RegionPushOverride));
parcelDataMap.Add("RentPrice", OSD.FromInteger(parcelPropertiesPacket.ParcelData.RentPrice));
parcelDataMap.Add("RequestResult", OSD.FromInteger(parcelPropertiesPacket.ParcelData.RequestResult));
parcelDataMap.Add("SalePrice", OSD.FromInteger(parcelPropertiesPacket.ParcelData.SalePrice));
parcelDataMap.Add("SelectedPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.SelectedPrims));
parcelDataMap.Add("SelfCount", OSD.FromInteger(parcelPropertiesPacket.ParcelData.SelfCount));
parcelDataMap.Add("SequenceID", OSD.FromInteger(parcelPropertiesPacket.ParcelData.SequenceID));
parcelDataMap.Add("SimWideMaxPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.SimWideMaxPrims));
parcelDataMap.Add("SimWideTotalPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.SimWideTotalPrims));
parcelDataMap.Add("SnapSelection", OSD.FromBoolean(parcelPropertiesPacket.ParcelData.SnapSelection));
parcelDataMap.Add("SnapshotID", OSD.FromUUID(parcelPropertiesPacket.ParcelData.SnapshotID));
parcelDataMap.Add("Status", OSD.FromInteger((int)parcelPropertiesPacket.ParcelData.Status));
parcelDataMap.Add("TotalPrims", OSD.FromInteger(parcelPropertiesPacket.ParcelData.TotalPrims));
OSDArray UserLocation = new OSDArray(3);
UserLocation.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.UserLocation.X));
UserLocation.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.UserLocation.Y));
UserLocation.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.UserLocation.Z));
parcelDataMap.Add("UserLocation", UserLocation);
OSDArray UserLookAt = new OSDArray(3);
UserLookAt.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.UserLookAt.X));
UserLookAt.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.UserLookAt.Y));
UserLookAt.Add(OSD.FromReal(parcelPropertiesPacket.ParcelData.UserLookAt.Z));
parcelDataMap.Add("UserLookAt", UserLookAt);
parcelData.Add(parcelDataMap);
body.Add("ParcelData", parcelData);
parcelProperties.Add("body", body);
parcelProperties.Add("message", OSD.FromString("ParcelProperties"));
return parcelProperties;
}
public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket)
{
OSDMap groupUpdate = new OSDMap();
@@ -495,5 +386,14 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
return placesReply;
}
public static OSD ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage)
{
OSDMap message = new OSDMap();
message.Add("message", OSD.FromString("ParcelProperties"));
OSD message_body = parcelPropertiesMessage.Serialize();
message.Add("body", message_body);
return message;
}
}
}

View File

@@ -549,7 +549,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
}
if (!m_Scene.Permissions.CanRezObject(
group.Children.Count, remoteClient.AgentId, pos)
group.PrimCount, remoteClient.AgentId, pos)
&& !attachment)
{
// The client operates in no fail mode. It will
@@ -629,7 +629,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
rootPart.Name = item.Name;
rootPart.Description = item.Description;
List<SceneObjectPart> partList = new List<SceneObjectPart>(group.Children.Values);
List<SceneObjectPart> partList = null;
lock (group.Children)
partList = new List<SceneObjectPart>(group.Children.Values);
group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0)

View File

@@ -27,15 +27,12 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
using Nini.Config;
using log4net;
using OpenSim.Framework;
using OpenSim.Services.Interfaces;
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
{
public abstract class BaseInventoryConnector : IInventoryService

View File

@@ -161,6 +161,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
/// <returns></returns>
public InventoryFolderBase GetFolderForType(UUID userID, AssetType type)
{
m_log.DebugFormat("[INVENTORY CACHE]: Getting folder for asset type {0} for user {1}", type, userID);
Dictionary<AssetType, InventoryFolderBase> folders = null;
lock (m_InventoryCache)
@@ -177,8 +179,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
if ((folders != null) && folders.ContainsKey(type))
{
m_log.DebugFormat(
"[INVENTORY CACHE]: Returning folder {0} as type {1} for {2}", folders[type], type, userID);
return folders[type];
}
m_log.WarnFormat("[INVENTORY CACHE]: Could not find folder for system type {0} for {1}", type, userID);
return null;
}

View File

@@ -216,13 +216,40 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return m_InventoryService.PurgeFolder(folder);
}
/// <summary>
/// Add a new item to the user's inventory
/// </summary>
/// <param name="item"></param>
/// <returns>true if the item was successfully added</returns>
public bool AddItem(InventoryItemBase item)
{
// m_log.DebugFormat(
// "[LOCAL INVENTORY SERVICES CONNECTOR]: Adding inventory item {0} to user {1} folder {2}",
// item.Name, item.Owner, item.Folder);
if (UUID.Zero == item.Folder)
{
InventoryFolderBase f = m_InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType);
if (f != null)
{
// m_log.DebugFormat(
// "[LOCAL INVENTORY SERVICES CONNECTOR]: Found folder {0} type {1} for item {2}",
// f.Name, (AssetType)f.Type, item.Name);
item.Folder = f.ID;
}
else
{
f = m_InventoryService.GetRootFolder(item.Owner);
if (f != null)
{
item.Folder = f.ID;
}
else
{
// m_log.WarnFormat(
// "[LOCAL INVENTORY SERVICES CONNECTOR]: Could not find root folder for {0} when trying to add item {1} with no parent folder specified",
// item.Owner, item.Name);
return false;
}
}
}
return m_InventoryService.AddItem(item);
}
@@ -236,7 +263,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return m_InventoryService.UpdateItem(item);
}
public bool MoveItems(UUID ownerID, List<InventoryItemBase> items)
{
return m_InventoryService.MoveItems(ownerID, items);

View File

@@ -75,7 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
base.Init(source);
}
#region ISharedRegionModule
public void Initialise(IConfigSource source)

View File

@@ -228,6 +228,30 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
{
if (item == null)
return false;
if (UUID.Zero == item.Folder)
{
InventoryFolderBase f = m_RemoteConnector.GetFolderForType(item.Owner, (AssetType)item.AssetType);
if (f != null)
{
item.Folder = f.ID;
}
else
{
f = m_RemoteConnector.GetRootFolder(item.Owner);
if (f != null)
{
item.Folder = f.ID;
}
else
{
m_log.WarnFormat(
"[LOCAL INVENTORY SERVICES CONNECTOR]: Could not find root folder for {0} when trying to add item {1} with no parent folder specified",
item.Owner, item.Name);
return false;
}
}
}
return m_RemoteConnector.AddItem(item);
}
@@ -294,9 +318,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return m_RemoteConnector.GetAssetPermissions(userID, assetID);
}
#endregion
}
}
}

View File

@@ -243,7 +243,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
// to the same scene (when this is possible).
sceneObject.ResetIDs();
foreach (SceneObjectPart part in sceneObject.Children.Values)
List<SceneObjectPart> partList = null;
lock (sceneObject.Children)
partList = new List<SceneObjectPart>(sceneObject.Children.Values);
foreach (SceneObjectPart part in partList)
{
if (!ResolveUserUuid(part.CreatorID))
part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
@@ -261,11 +265,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver
// Fix ownership/creator of inventory items
// Not doing so results in inventory items
// being no copy/no mod for everyone
part.TaskInventory.LockItemsForRead(true);
TaskInventoryDictionary inv = part.TaskInventory;
foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
lock (part.TaskInventory)
{
if (!ResolveUserUuid(kvp.Value.OwnerID))
if (!ResolveUserUuid(part.CreatorID))
part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
if (!ResolveUserUuid(part.OwnerID))
part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
if (!ResolveUserUuid(part.LastOwnerID))
part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
// And zap any troublesome sit target information
part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
part.SitTargetPosition = new Vector3(0, 0, 0);
// Fix ownership/creator of inventory items
// Not doing so results in inventory items
// being no copy/no mod for everyone
part.TaskInventory.LockItemsForRead(true);
TaskInventoryDictionary inv = part.TaskInventory;
foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
{
if (!ResolveUserUuid(kvp.Value.OwnerID))
{
@@ -276,8 +296,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
kvp.Value.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
}
}
part.TaskInventory.LockItemsForRead(false);
}
part.TaskInventory.LockItemsForRead(false);
}
if (m_scene.AddRestoredSceneObject(sceneObject, true, false))

View File

@@ -684,6 +684,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
args.useEstateSun = m_scene.RegionInfo.RegionSettings.UseEstateSun;
args.waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
args.simName = m_scene.RegionInfo.RegionName;
args.regionType = m_scene.RegionInfo.RegionType;
remote_client.SendRegionInfoToEstateMenu(args);
}

View File

@@ -33,6 +33,8 @@ using System.Reflection;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Messages.Linden;
using OpenSim.Framework;
using OpenSim.Framework.Capabilities;
using OpenSim.Framework.Servers;
@@ -1078,7 +1080,6 @@ namespace OpenSim.Region.CoreModules.World.Land
{
for (int y = 0; y < inc_y; y++)
{
ILandObject currentParcel = GetLandObject(start_x + x, start_y + y);
if (currentParcel != null)
@@ -1378,8 +1379,68 @@ namespace OpenSim.Region.CoreModules.World.Land
{
return RemoteParcelRequest(request, path, param, agentID, caps);
}));
UUID parcelCapID = UUID.Random();
caps.RegisterHandler("ParcelPropertiesUpdate",
new RestStreamHandler("POST", "/CAPS/" + parcelCapID,
delegate(string request, string path, string param,
OSHttpRequest httpRequest, OSHttpResponse httpResponse)
{
return ProcessPropertiesUpdate(request, path, param, agentID, caps);
}));
}
private string ProcessPropertiesUpdate(string request, string path, string param, UUID agentID, Caps caps)
{
IClientAPI client;
if ( ! m_scene.TryGetClient(agentID, out client) ) {
m_log.WarnFormat("[LAND] unable to retrieve IClientAPI for {0}", agentID.ToString() );
return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty());
}
ParcelPropertiesUpdateMessage properties = new ParcelPropertiesUpdateMessage();
OpenMetaverse.StructuredData.OSDMap args = (OpenMetaverse.StructuredData.OSDMap) OSDParser.DeserializeLLSDXml(request);
properties.Deserialize(args);
LandUpdateArgs land_update = new LandUpdateArgs();
int parcelID = properties.LocalID;
land_update.AuthBuyerID = properties.AuthBuyerID;
land_update.Category = properties.Category;
land_update.Desc = properties.Desc;
land_update.GroupID = properties.GroupID;
land_update.LandingType = (byte) properties.Landing;
land_update.MediaAutoScale = (byte) Convert.ToInt32(properties.MediaAutoScale);
land_update.MediaID = properties.MediaID;
land_update.MediaURL = properties.MediaURL;
land_update.MusicURL = properties.MusicURL;
land_update.Name = properties.Name;
land_update.ParcelFlags = (uint) properties.ParcelFlags;
land_update.PassHours = (int) properties.PassHours;
land_update.PassPrice = (int) properties.PassPrice;
land_update.SalePrice = (int) properties.SalePrice;
land_update.SnapshotID = properties.SnapshotID;
land_update.UserLocation = properties.UserLocation;
land_update.UserLookAt = properties.UserLookAt;
land_update.MediaDescription = properties.MediaDesc;
land_update.MediaType = properties.MediaType;
land_update.MediaWidth = properties.MediaWidth;
land_update.MediaHeight = properties.MediaHeight;
land_update.MediaLoop = properties.MediaLoop;
land_update.ObscureMusic = properties.ObscureMusic;
land_update.ObscureMedia = properties.ObscureMedia;
ILandObject land;
lock (m_landList)
{
m_landList.TryGetValue(parcelID, out land);
}
if (land != null) {
land.UpdateLandProperties(land_update, client);
} else {
m_log.WarnFormat("[LAND] unable to find parcelID {0}", parcelID);
}
return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty());
}
// we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the
// "real" parcelID, because we wouldn't be able to map that to the region the parcel belongs to.
// So, we create a "fake" parcelID by using the regionHandle (64 bit), and the local (integer) x

File diff suppressed because it is too large Load Diff

View File

@@ -128,7 +128,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
group.SetOwnerId(remoteClient.AgentId);
group.SetRootPartOwner(part, remoteClient.AgentId, remoteClient.ActiveGroupId);
List<SceneObjectPart> partList = new List<SceneObjectPart>(group.Children.Values);
List<SceneObjectPart> partList = null;
lock (group.Children)
partList = new List<SceneObjectPart>(group.Children.Values);
if (m_scene.Permissions.PropagatePermissions())
{

View File

@@ -227,8 +227,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
{
SceneObjectGroup mapdot = (SceneObjectGroup)obj;
Color mapdotspot = Color.Gray; // Default color when prim color is white
// Loop over prim in group
foreach (SceneObjectPart part in mapdot.Children.Values)
// Loop over prim in group
List<SceneObjectPart> partList = null;
lock (mapdot.Children)
partList = new List<SceneObjectPart>(mapdot.Children.Values);
foreach (SceneObjectPart part in partList)
{
if (part == null)
continue;