Again, completely revamp the unlink code to finally allow unlinking

arbitrary combinations of root and child prims from one or multiple
link sets. Please test throughly and consider things UNSTABLE until
this is proven out.
0.6.5-rc1
Melanie Thielker 2009-04-29 15:54:16 +00:00
parent 84701701ef
commit d604cd284e
2 changed files with 149 additions and 142 deletions

View File

@ -1588,107 +1588,109 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void DelinkObjects(List<uint> primIds, bool sendEvents) protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
{ {
SceneObjectGroup parentPrim = null; List<SceneObjectPart> childParts = new List<SceneObjectPart>();
// Find the root prim among the prim ids we've been given List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
for (int i = 0; i < primIds.Count; i++) List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
// Look them all up in one go, since that is comparatively expensive
//
foreach (uint primID in primIds)
{ {
// Get the group for this prim and check that it is the parent SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID);
parentPrim = GetGroupByPrim(primIds[i]); if (part != null)
if (parentPrim != null && parentPrim.LocalId == primIds[i])
{ {
primIds.RemoveAt(i); if (part.LinkNum < 2) // Root or single
break; rootParts.Add(part);
} else
} childParts.Add(part);
if (parentPrim != null) SceneObjectGroup group = part.ParentGroup;
{ if (!affectedGroups.Contains(group))
foreach (uint childPrimId in primIds) affectedGroups.Add(group);
{
parentPrim.DelinkFromGroup(childPrimId, sendEvents);
}
if (parentPrim.Children.Count == 1)
{
// The link set has been completely torn down
// This is the case if you select a link set and delink
//
parentPrim.RootPart.LinkNum = 0;
if (sendEvents)
parentPrim.TriggerScriptChangedEvent(Changed.LINK);
} }
else else
{ {
// The link set has prims remaining. This path is taken m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID);
// when a subset of a link set's prims are selected
// and the root prim is part of that selection
//
List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
List<uint> unlink_ids = new List<uint>();
foreach (SceneObjectPart unlink_part in parts)
unlink_ids.Add(unlink_part.LocalId);
// Tear down the remaining link set
//
if (unlink_ids.Count == 2)
{
DelinkObjects(unlink_ids, true);
return;
}
DelinkObjects(unlink_ids, false);
// Send event to root prim, then we're done with it
parentPrim.TriggerScriptChangedEvent(Changed.LINK);
unlink_ids.Remove(parentPrim.RootPart.LocalId);
foreach (uint localId in unlink_ids)
{
SceneObjectPart nr = GetSceneObjectPart(localId);
nr.UpdateFlag = 0;
}
uint newRoot = unlink_ids[0];
unlink_ids.Remove(newRoot);
LinkObjects(null, newRoot, unlink_ids);
} }
} }
else
foreach (SceneObjectPart child in childParts)
{ {
// The selected prims were all child prims. Edit linked parts // Unlink all child parts from their groups
// without the root prim selected will get us here
// //
List<SceneObjectGroup> parentGroups = new List<SceneObjectGroup>(); child.ParentGroup.DelinkFromGroup(child, sendEvents);
}
// If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow foreach (SceneObjectPart root in rootParts)
// We know that this is not the root prim now essentially, so we don't have to worry about remapping {
// which one is the root prim // In most cases, this will run only one time, and the prim
bool delinkedSomething = false; // will be a solo prim
for (int i = 0; i < primIds.Count; i++) // 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)
{ {
SceneObjectGroup parent = GetGroupByPrim(primIds[i]); // Unlink the remaining set
parent.DelinkFromGroup(primIds[i]); //
delinkedSomething = true; bool sendEventsToRemainder = true;
if (!parentGroups.Contains(parent)) if (numChildren > 1)
parentGroups.Add(parent); sendEventsToRemainder = false;
}
if (!delinkedSomething) foreach (SceneObjectPart p in newSet)
{
m_log.InfoFormat("[SCENE]: " +
"DelinkObjects(): Could not find a root prim out of {0} as given to a delink request!",
primIds);
}
else
{
foreach (SceneObjectGroup g in parentGroups)
{ {
g.TriggerScriptChangedEvent(Changed.LINK); if (p != group.RootPart)
group.DelinkFromGroup(p, sendEventsToRemainder);
}
// If there is more than one prim remaining, we
// need to re-link
//
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
//
foreach (SceneObjectGroup g in affectedGroups)
{
g.TriggerScriptChangedEvent(Changed.LINK);
g.ScheduleGroupForFullUpdate();
}
} }
protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID) protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)

View File

@ -2237,64 +2237,9 @@ namespace OpenSim.Region.Framework.Scenes
{ {
SceneObjectPart linkPart = GetChildPart(partID); SceneObjectPart linkPart = GetChildPart(partID);
if (null != linkPart) if (linkPart != null)
{ {
linkPart.ClearUndoState(); DelinkFromGroup(linkPart, sendEvents);
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
Quaternion worldRot = linkPart.GetWorldRotation();
// Remove the part from this object
lock (m_parts)
{
m_parts.Remove(linkPart.UUID);
}
if (m_parts.Count == 1 && RootPart != null) //Single prim is left
RootPart.LinkNum = 0;
else
{
foreach (SceneObjectPart p in m_parts.Values)
{
if (p.LinkNum > linkPart.LinkNum)
p.LinkNum--;
}
}
linkPart.ParentID = 0;
linkPart.LinkNum = 0;
if (linkPart.PhysActor != null)
{
m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
}
// We need to reset the child part's position
// ready for life as a separate object after being a part of another object
Quaternion parentRot = m_rootPart.RotationOffset;
Vector3 axPos = linkPart.OffsetPosition;
axPos *= parentRot;
linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
linkPart.OffsetPosition = new Vector3(0, 0, 0);
linkPart.RotationOffset = worldRot;
SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
m_scene.AddNewSceneObject(objectGroup, true);
if (sendEvents)
linkPart.TriggerScriptChangedEvent(Changed.LINK);
linkPart.Rezzed = RootPart.Rezzed;
HasGroupChanged = true;
ScheduleGroupForFullUpdate();
} }
else else
{ {
@ -2304,6 +2249,66 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
public void DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents)
{
linkPart.ClearUndoState();
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
Quaternion worldRot = linkPart.GetWorldRotation();
// Remove the part from this object
lock (m_parts)
{
m_parts.Remove(linkPart.UUID);
}
if (m_parts.Count == 1 && RootPart != null) //Single prim is left
RootPart.LinkNum = 0;
else
{
foreach (SceneObjectPart p in m_parts.Values)
{
if (p.LinkNum > linkPart.LinkNum)
p.LinkNum--;
}
}
linkPart.ParentID = 0;
linkPart.LinkNum = 0;
if (linkPart.PhysActor != null)
{
m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
}
// We need to reset the child part's position
// ready for life as a separate object after being a part of another object
Quaternion parentRot = m_rootPart.RotationOffset;
Vector3 axPos = linkPart.OffsetPosition;
axPos *= parentRot;
linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
linkPart.OffsetPosition = new Vector3(0, 0, 0);
linkPart.RotationOffset = worldRot;
SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
m_scene.AddNewSceneObject(objectGroup, true);
if (sendEvents)
linkPart.TriggerScriptChangedEvent(Changed.LINK);
linkPart.Rezzed = RootPart.Rezzed;
HasGroupChanged = true;
ScheduleGroupForFullUpdate();
}
/// <summary> /// <summary>
/// Stop this object from being persisted over server restarts. /// Stop this object from being persisted over server restarts.
/// </summary> /// </summary>