Lock updates out while linking and unlinking
parent
ceccfe02d0
commit
fbefa8273b
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
@ -96,6 +97,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>();
|
protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>();
|
||||||
private readonly Object m_dictionary_lock = new Object();
|
private readonly Object m_dictionary_lock = new Object();
|
||||||
|
|
||||||
|
private Object m_updateLock = new Object();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected internal SceneGraph(Scene parent, RegionInfo regInfo)
|
protected internal SceneGraph(Scene parent, RegionInfo regInfo)
|
||||||
|
@ -369,6 +372,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal void UpdateObjectGroups()
|
protected internal void UpdateObjectGroups()
|
||||||
{
|
{
|
||||||
|
if (!Monitor.TryEnter(m_updateLock))
|
||||||
|
return;
|
||||||
|
|
||||||
List<SceneObjectGroup> updates;
|
List<SceneObjectGroup> updates;
|
||||||
|
|
||||||
// Some updates add more updates to the updateList.
|
// Some updates add more updates to the updateList.
|
||||||
|
@ -395,6 +401,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
"[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e);
|
"[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Monitor.Exit(m_updateLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal void AddPhysicalPrim(int number)
|
protected internal void AddPhysicalPrim(int number)
|
||||||
|
@ -1555,56 +1562,59 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <param name="childPrims"></param>
|
/// <param name="childPrims"></param>
|
||||||
protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds)
|
protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds)
|
||||||
{
|
{
|
||||||
SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId);
|
lock (m_updateLock)
|
||||||
|
|
||||||
List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
|
|
||||||
if (parentGroup != null)
|
|
||||||
{
|
{
|
||||||
// We do this in reverse to get the link order of the prims correct
|
SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId);
|
||||||
for (int i = childPrimIds.Count - 1; i >= 0; i--)
|
|
||||||
|
List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
|
||||||
|
if (parentGroup != null)
|
||||||
{
|
{
|
||||||
SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]);
|
// We do this in reverse to get the link order of the prims correct
|
||||||
if (child != null)
|
for (int i = childPrimIds.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
// Make sure no child prim is set for sale
|
SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]);
|
||||||
// So that, on delink, no prims are unwittingly
|
if (child != null)
|
||||||
// left for sale and sold off
|
{
|
||||||
child.RootPart.ObjectSaleType = 0;
|
// Make sure no child prim is set for sale
|
||||||
child.RootPart.SalePrice = 10;
|
// So that, on delink, no prims are unwittingly
|
||||||
childGroups.Add(child);
|
// left for sale and sold off
|
||||||
|
child.RootPart.ObjectSaleType = 0;
|
||||||
|
child.RootPart.SalePrice = 10;
|
||||||
|
childGroups.Add(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
{
|
|
||||||
return; // parent is null so not in this region
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (SceneObjectGroup child in childGroups)
|
|
||||||
{
|
|
||||||
parentGroup.LinkToGroup(child);
|
|
||||||
|
|
||||||
// this is here so physics gets updated!
|
|
||||||
// Don't remove! Bad juju! Stay away! or fix physics!
|
|
||||||
child.AbsolutePosition = child.AbsolutePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to explicitly resend the newly link prim's object properties since no other actions
|
|
||||||
// occur on link to invoke this elsewhere (such as object selection)
|
|
||||||
parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected);
|
|
||||||
parentGroup.TriggerScriptChangedEvent(Changed.LINK);
|
|
||||||
parentGroup.HasGroupChanged = true;
|
|
||||||
parentGroup.ScheduleGroupForFullUpdate();
|
|
||||||
|
|
||||||
if (client != null)
|
|
||||||
{
|
|
||||||
parentGroup.GetProperties(client);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (ScenePresence p in GetScenePresences())
|
|
||||||
{
|
{
|
||||||
parentGroup.GetProperties(p.ControllingClient);
|
return; // parent is null so not in this region
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (SceneObjectGroup child in childGroups)
|
||||||
|
{
|
||||||
|
parentGroup.LinkToGroup(child);
|
||||||
|
|
||||||
|
// this is here so physics gets updated!
|
||||||
|
// Don't remove! Bad juju! Stay away! or fix physics!
|
||||||
|
child.AbsolutePosition = child.AbsolutePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to explicitly resend the newly link prim's object properties since no other actions
|
||||||
|
// occur on link to invoke this elsewhere (such as object selection)
|
||||||
|
parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected);
|
||||||
|
parentGroup.TriggerScriptChangedEvent(Changed.LINK);
|
||||||
|
parentGroup.HasGroupChanged = true;
|
||||||
|
parentGroup.ScheduleGroupForFullUpdate();
|
||||||
|
|
||||||
|
if (client != null)
|
||||||
|
{
|
||||||
|
parentGroup.GetProperties(client);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (ScenePresence p in GetScenePresences())
|
||||||
|
{
|
||||||
|
parentGroup.GetProperties(p.ControllingClient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1620,109 +1630,112 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
|
protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
|
||||||
{
|
{
|
||||||
List<SceneObjectPart> childParts = new List<SceneObjectPart>();
|
lock (m_updateLock)
|
||||||
List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
|
|
||||||
List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
|
|
||||||
// Look them all up in one go, since that is comparatively expensive
|
|
||||||
//
|
|
||||||
foreach (uint primID in primIds)
|
|
||||||
{
|
{
|
||||||
SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID);
|
List<SceneObjectPart> childParts = new List<SceneObjectPart>();
|
||||||
if (part != null)
|
List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
|
||||||
{
|
List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
|
||||||
if (part.LinkNum < 2) // Root or single
|
// Look them all up in one go, since that is comparatively expensive
|
||||||
rootParts.Add(part);
|
|
||||||
else
|
|
||||||
childParts.Add(part);
|
|
||||||
|
|
||||||
SceneObjectGroup group = part.ParentGroup;
|
|
||||||
if (!affectedGroups.Contains(group))
|
|
||||||
affectedGroups.Add(group);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (SceneObjectPart child in childParts)
|
|
||||||
{
|
|
||||||
// Unlink all child parts from their groups
|
|
||||||
//
|
//
|
||||||
child.ParentGroup.DelinkFromGroup(child, sendEvents);
|
foreach (uint primID in primIds)
|
||||||
}
|
|
||||||
|
|
||||||
foreach (SceneObjectPart root in rootParts)
|
|
||||||
{
|
|
||||||
// In most cases, this will run only one time, and the prim
|
|
||||||
// will be a solo prim
|
|
||||||
// However, editing linked parts and unlinking may be different
|
|
||||||
//
|
|
||||||
SceneObjectGroup group = root.ParentGroup;
|
|
||||||
List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Children.Values);
|
|
||||||
int numChildren = group.Children.Count;
|
|
||||||
|
|
||||||
// If there are prims left in a link set, but the root is
|
|
||||||
// slated for unlink, we need to do this
|
|
||||||
//
|
|
||||||
if (numChildren != 1)
|
|
||||||
{
|
{
|
||||||
// Unlink the remaining set
|
SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID);
|
||||||
//
|
if (part != null)
|
||||||
bool sendEventsToRemainder = true;
|
|
||||||
if (numChildren > 1)
|
|
||||||
sendEventsToRemainder = false;
|
|
||||||
|
|
||||||
foreach (SceneObjectPart p in newSet)
|
|
||||||
{
|
{
|
||||||
if (p != group.RootPart)
|
if (part.LinkNum < 2) // Root or single
|
||||||
group.DelinkFromGroup(p, sendEventsToRemainder);
|
rootParts.Add(part);
|
||||||
|
else
|
||||||
|
childParts.Add(part);
|
||||||
|
|
||||||
|
SceneObjectGroup group = part.ParentGroup;
|
||||||
|
if (!affectedGroups.Contains(group))
|
||||||
|
affectedGroups.Add(group);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// If there is more than one prim remaining, we
|
|
||||||
// need to re-link
|
|
||||||
//
|
|
||||||
if (numChildren > 2)
|
|
||||||
{
|
{
|
||||||
// Remove old root
|
m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID);
|
||||||
//
|
}
|
||||||
if (newSet.Contains(root))
|
}
|
||||||
newSet.Remove(root);
|
|
||||||
|
|
||||||
// Preserve link ordering
|
foreach (SceneObjectPart child in childParts)
|
||||||
|
{
|
||||||
|
// Unlink all child parts from their groups
|
||||||
|
//
|
||||||
|
child.ParentGroup.DelinkFromGroup(child, sendEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (SceneObjectPart root in rootParts)
|
||||||
|
{
|
||||||
|
// In most cases, this will run only one time, and the prim
|
||||||
|
// will be a solo prim
|
||||||
|
// However, editing linked parts and unlinking may be different
|
||||||
|
//
|
||||||
|
SceneObjectGroup group = root.ParentGroup;
|
||||||
|
List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Children.Values);
|
||||||
|
int numChildren = group.Children.Count;
|
||||||
|
|
||||||
|
// If there are prims left in a link set, but the root is
|
||||||
|
// slated for unlink, we need to do this
|
||||||
|
//
|
||||||
|
if (numChildren != 1)
|
||||||
|
{
|
||||||
|
// Unlink the remaining set
|
||||||
//
|
//
|
||||||
newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
|
bool sendEventsToRemainder = true;
|
||||||
|
if (numChildren > 1)
|
||||||
|
sendEventsToRemainder = false;
|
||||||
|
|
||||||
|
foreach (SceneObjectPart p in newSet)
|
||||||
{
|
{
|
||||||
return a.LinkNum.CompareTo(b.LinkNum);
|
if (p != group.RootPart)
|
||||||
});
|
group.DelinkFromGroup(p, sendEventsToRemainder);
|
||||||
|
|
||||||
// Determine new root
|
|
||||||
//
|
|
||||||
SceneObjectPart newRoot = newSet[0];
|
|
||||||
newSet.RemoveAt(0);
|
|
||||||
|
|
||||||
List<uint> linkIDs = new List<uint>();
|
|
||||||
|
|
||||||
foreach (SceneObjectPart newChild in newSet)
|
|
||||||
{
|
|
||||||
newChild.UpdateFlag = 0;
|
|
||||||
linkIDs.Add(newChild.LocalId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkObjects(null, newRoot.LocalId, linkIDs);
|
// If there is more than one prim remaining, we
|
||||||
if (!affectedGroups.Contains(newRoot.ParentGroup))
|
// need to re-link
|
||||||
affectedGroups.Add(newRoot.ParentGroup);
|
//
|
||||||
|
if (numChildren > 2)
|
||||||
|
{
|
||||||
|
// Remove old root
|
||||||
|
//
|
||||||
|
if (newSet.Contains(root))
|
||||||
|
newSet.Remove(root);
|
||||||
|
|
||||||
|
// Preserve link ordering
|
||||||
|
//
|
||||||
|
newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
|
||||||
|
{
|
||||||
|
return a.LinkNum.CompareTo(b.LinkNum);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Determine new root
|
||||||
|
//
|
||||||
|
SceneObjectPart newRoot = newSet[0];
|
||||||
|
newSet.RemoveAt(0);
|
||||||
|
|
||||||
|
List<uint> linkIDs = new List<uint>();
|
||||||
|
|
||||||
|
foreach (SceneObjectPart newChild in newSet)
|
||||||
|
{
|
||||||
|
newChild.UpdateFlag = 0;
|
||||||
|
linkIDs.Add(newChild.LocalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkObjects(null, newRoot.LocalId, linkIDs);
|
||||||
|
if (!affectedGroups.Contains(newRoot.ParentGroup))
|
||||||
|
affectedGroups.Add(newRoot.ParentGroup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, trigger events in the roots
|
// Finally, trigger events in the roots
|
||||||
//
|
//
|
||||||
foreach (SceneObjectGroup g in affectedGroups)
|
foreach (SceneObjectGroup g in affectedGroups)
|
||||||
{
|
{
|
||||||
g.TriggerScriptChangedEvent(Changed.LINK);
|
g.TriggerScriptChangedEvent(Changed.LINK);
|
||||||
g.HasGroupChanged = true; // Persist
|
g.HasGroupChanged = true; // Persist
|
||||||
g.ScheduleGroupForFullUpdate();
|
g.ScheduleGroupForFullUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue