diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 264 |
1 files changed, 146 insertions, 118 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 2fdb48d..f74fd5d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Threading; | ||
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using OpenMetaverse; | 32 | using OpenMetaverse; |
@@ -96,6 +97,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
96 | protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>(); | 97 | protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>(); |
97 | private readonly Object m_dictionary_lock = new Object(); | 98 | private readonly Object m_dictionary_lock = new Object(); |
98 | 99 | ||
100 | private Object m_updateLock = new Object(); | ||
101 | |||
99 | #endregion | 102 | #endregion |
100 | 103 | ||
101 | protected internal SceneGraph(Scene parent, RegionInfo regInfo) | 104 | protected internal SceneGraph(Scene parent, RegionInfo regInfo) |
@@ -369,6 +372,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
369 | /// </summary> | 372 | /// </summary> |
370 | protected internal void UpdateObjectGroups() | 373 | protected internal void UpdateObjectGroups() |
371 | { | 374 | { |
375 | if (!Monitor.TryEnter(m_updateLock)) | ||
376 | return; | ||
377 | |||
372 | List<SceneObjectGroup> updates; | 378 | List<SceneObjectGroup> updates; |
373 | 379 | ||
374 | // Some updates add more updates to the updateList. | 380 | // Some updates add more updates to the updateList. |
@@ -395,6 +401,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
395 | "[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e); | 401 | "[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e); |
396 | } | 402 | } |
397 | } | 403 | } |
404 | Monitor.Exit(m_updateLock); | ||
398 | } | 405 | } |
399 | 406 | ||
400 | protected internal void AddPhysicalPrim(int number) | 407 | protected internal void AddPhysicalPrim(int number) |
@@ -1555,55 +1562,65 @@ namespace OpenSim.Region.Framework.Scenes | |||
1555 | /// <param name="childPrims"></param> | 1562 | /// <param name="childPrims"></param> |
1556 | protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds) | 1563 | protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds) |
1557 | { | 1564 | { |
1558 | SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId); | 1565 | Monitor.Enter(m_updateLock); |
1559 | 1566 | try | |
1560 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); | ||
1561 | if (parentGroup != null) | ||
1562 | { | 1567 | { |
1563 | // We do this in reverse to get the link order of the prims correct | 1568 | SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId); |
1564 | for (int i = childPrimIds.Count - 1; i >= 0; i--) | 1569 | |
1570 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); | ||
1571 | if (parentGroup != null) | ||
1565 | { | 1572 | { |
1566 | SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]); | 1573 | // We do this in reverse to get the link order of the prims correct |
1567 | if (child != null) | 1574 | for (int i = childPrimIds.Count - 1; i >= 0; i--) |
1568 | { | 1575 | { |
1569 | // Make sure no child prim is set for sale | 1576 | SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]); |
1570 | // So that, on delink, no prims are unwittingly | 1577 | if (child != null) |
1571 | // left for sale and sold off | 1578 | { |
1572 | child.RootPart.ObjectSaleType = 0; | 1579 | // Make sure no child prim is set for sale |
1573 | child.RootPart.SalePrice = 10; | 1580 | // So that, on delink, no prims are unwittingly |
1574 | childGroups.Add(child); | 1581 | // left for sale and sold off |
1582 | child.RootPart.ObjectSaleType = 0; | ||
1583 | child.RootPart.SalePrice = 10; | ||
1584 | childGroups.Add(child); | ||
1585 | } | ||
1575 | } | 1586 | } |
1576 | } | 1587 | } |
1577 | } | 1588 | else |
1578 | else | 1589 | { |
1579 | { | 1590 | return; // parent is null so not in this region |
1580 | return; // parent is null so not in this region | 1591 | } |
1581 | } | ||
1582 | 1592 | ||
1583 | foreach (SceneObjectGroup child in childGroups) | 1593 | foreach (SceneObjectGroup child in childGroups) |
1584 | { | 1594 | { |
1585 | parentGroup.LinkToGroup(child); | 1595 | parentGroup.LinkToGroup(child); |
1586 | 1596 | ||
1587 | // this is here so physics gets updated! | 1597 | // this is here so physics gets updated! |
1588 | // Don't remove! Bad juju! Stay away! or fix physics! | 1598 | // Don't remove! Bad juju! Stay away! or fix physics! |
1589 | child.AbsolutePosition = child.AbsolutePosition; | 1599 | child.AbsolutePosition = child.AbsolutePosition; |
1590 | } | 1600 | } |
1591 | 1601 | ||
1592 | // We need to explicitly resend the newly link prim's object properties since no other actions | 1602 | // We need to explicitly resend the newly link prim's object properties since no other actions |
1593 | // occur on link to invoke this elsewhere (such as object selection) | 1603 | // occur on link to invoke this elsewhere (such as object selection) |
1594 | parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected); | 1604 | parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected); |
1595 | parentGroup.TriggerScriptChangedEvent(Changed.LINK); | 1605 | parentGroup.TriggerScriptChangedEvent(Changed.LINK); |
1596 | 1606 | parentGroup.HasGroupChanged = true; | |
1597 | if (client != null) | 1607 | parentGroup.ScheduleGroupForFullUpdate(); |
1598 | { | 1608 | |
1599 | parentGroup.GetProperties(client); | 1609 | // if (client != null) |
1610 | // { | ||
1611 | // parentGroup.GetProperties(client); | ||
1612 | // } | ||
1613 | // else | ||
1614 | // { | ||
1615 | // foreach (ScenePresence p in GetScenePresences()) | ||
1616 | // { | ||
1617 | // parentGroup.GetProperties(p.ControllingClient); | ||
1618 | // } | ||
1619 | // } | ||
1600 | } | 1620 | } |
1601 | else | 1621 | finally |
1602 | { | 1622 | { |
1603 | foreach (ScenePresence p in GetScenePresences()) | 1623 | Monitor.Exit(m_updateLock); |
1604 | { | ||
1605 | parentGroup.GetProperties(p.ControllingClient); | ||
1606 | } | ||
1607 | } | 1624 | } |
1608 | } | 1625 | } |
1609 | 1626 | ||
@@ -1618,109 +1635,120 @@ namespace OpenSim.Region.Framework.Scenes | |||
1618 | 1635 | ||
1619 | protected internal void DelinkObjects(List<uint> primIds, bool sendEvents) | 1636 | protected internal void DelinkObjects(List<uint> primIds, bool sendEvents) |
1620 | { | 1637 | { |
1621 | List<SceneObjectPart> childParts = new List<SceneObjectPart>(); | 1638 | Monitor.Enter(m_updateLock); |
1622 | List<SceneObjectPart> rootParts = new List<SceneObjectPart>(); | 1639 | try |
1623 | List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>(); | ||
1624 | // Look them all up in one go, since that is comparatively expensive | ||
1625 | // | ||
1626 | foreach (uint primID in primIds) | ||
1627 | { | 1640 | { |
1628 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID); | 1641 | List<SceneObjectPart> childParts = new List<SceneObjectPart>(); |
1629 | if (part != null) | 1642 | List<SceneObjectPart> rootParts = new List<SceneObjectPart>(); |
1643 | List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>(); | ||
1644 | // Look them all up in one go, since that is comparatively expensive | ||
1645 | // | ||
1646 | foreach (uint primID in primIds) | ||
1630 | { | 1647 | { |
1631 | if (part.LinkNum < 2) // Root or single | 1648 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID); |
1632 | rootParts.Add(part); | 1649 | if (part != null) |
1650 | { | ||
1651 | if (part.ParentGroup.Children.Count != 1) // Skip single | ||
1652 | { | ||
1653 | if (part.LinkNum < 2) // Root | ||
1654 | rootParts.Add(part); | ||
1655 | else | ||
1656 | childParts.Add(part); | ||
1657 | |||
1658 | SceneObjectGroup group = part.ParentGroup; | ||
1659 | if (!affectedGroups.Contains(group)) | ||
1660 | affectedGroups.Add(group); | ||
1661 | } | ||
1662 | } | ||
1633 | else | 1663 | else |
1634 | childParts.Add(part); | 1664 | { |
1635 | 1665 | m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID); | |
1636 | SceneObjectGroup group = part.ParentGroup; | 1666 | } |
1637 | if (!affectedGroups.Contains(group)) | ||
1638 | affectedGroups.Add(group); | ||
1639 | } | 1667 | } |
1640 | else | 1668 | |
1669 | foreach (SceneObjectPart child in childParts) | ||
1641 | { | 1670 | { |
1642 | m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID); | 1671 | // Unlink all child parts from their groups |
1672 | // | ||
1673 | child.ParentGroup.DelinkFromGroup(child, sendEvents); | ||
1643 | } | 1674 | } |
1644 | } | ||
1645 | |||
1646 | foreach (SceneObjectPart child in childParts) | ||
1647 | { | ||
1648 | // Unlink all child parts from their groups | ||
1649 | // | ||
1650 | child.ParentGroup.DelinkFromGroup(child, sendEvents); | ||
1651 | } | ||
1652 | |||
1653 | foreach (SceneObjectPart root in rootParts) | ||
1654 | { | ||
1655 | // In most cases, this will run only one time, and the prim | ||
1656 | // will be a solo prim | ||
1657 | // However, editing linked parts and unlinking may be different | ||
1658 | // | ||
1659 | SceneObjectGroup group = root.ParentGroup; | ||
1660 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Children.Values); | ||
1661 | int numChildren = group.Children.Count; | ||
1662 | 1675 | ||
1663 | // If there are prims left in a link set, but the root is | 1676 | foreach (SceneObjectPart root in rootParts) |
1664 | // slated for unlink, we need to do this | ||
1665 | // | ||
1666 | if (numChildren != 1) | ||
1667 | { | 1677 | { |
1668 | // Unlink the remaining set | 1678 | // In most cases, this will run only one time, and the prim |
1679 | // will be a solo prim | ||
1680 | // However, editing linked parts and unlinking may be different | ||
1669 | // | 1681 | // |
1670 | bool sendEventsToRemainder = true; | 1682 | SceneObjectGroup group = root.ParentGroup; |
1671 | if (numChildren > 1) | 1683 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Children.Values); |
1672 | sendEventsToRemainder = false; | 1684 | int numChildren = group.Children.Count; |
1673 | |||
1674 | foreach (SceneObjectPart p in newSet) | ||
1675 | { | ||
1676 | if (p != group.RootPart) | ||
1677 | group.DelinkFromGroup(p, sendEventsToRemainder); | ||
1678 | } | ||
1679 | 1685 | ||
1680 | // If there is more than one prim remaining, we | 1686 | // If there are prims left in a link set, but the root is |
1681 | // need to re-link | 1687 | // slated for unlink, we need to do this |
1682 | // | 1688 | // |
1683 | if (numChildren > 2) | 1689 | if (numChildren != 1) |
1684 | { | 1690 | { |
1685 | // Remove old root | 1691 | // Unlink the remaining set |
1686 | // | 1692 | // |
1687 | if (newSet.Contains(root)) | 1693 | bool sendEventsToRemainder = true; |
1688 | newSet.Remove(root); | 1694 | if (numChildren > 1) |
1695 | sendEventsToRemainder = false; | ||
1689 | 1696 | ||
1690 | // Preserve link ordering | 1697 | foreach (SceneObjectPart p in newSet) |
1691 | // | ||
1692 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) | ||
1693 | { | 1698 | { |
1694 | return a.LinkNum.CompareTo(b.LinkNum); | 1699 | if (p != group.RootPart) |
1695 | }); | 1700 | group.DelinkFromGroup(p, sendEventsToRemainder); |
1701 | } | ||
1696 | 1702 | ||
1697 | // Determine new root | 1703 | // If there is more than one prim remaining, we |
1704 | // need to re-link | ||
1698 | // | 1705 | // |
1699 | SceneObjectPart newRoot = newSet[0]; | 1706 | if (numChildren > 2) |
1700 | newSet.RemoveAt(0); | 1707 | { |
1708 | // Remove old root | ||
1709 | // | ||
1710 | if (newSet.Contains(root)) | ||
1711 | newSet.Remove(root); | ||
1712 | |||
1713 | // Preserve link ordering | ||
1714 | // | ||
1715 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) | ||
1716 | { | ||
1717 | return a.LinkNum.CompareTo(b.LinkNum); | ||
1718 | }); | ||
1701 | 1719 | ||
1702 | List<uint> linkIDs = new List<uint>(); | 1720 | // Determine new root |
1721 | // | ||
1722 | SceneObjectPart newRoot = newSet[0]; | ||
1723 | newSet.RemoveAt(0); | ||
1703 | 1724 | ||
1704 | foreach (SceneObjectPart newChild in newSet) | 1725 | List<uint> linkIDs = new List<uint>(); |
1705 | { | 1726 | |
1706 | newChild.UpdateFlag = 0; | 1727 | foreach (SceneObjectPart newChild in newSet) |
1707 | linkIDs.Add(newChild.LocalId); | 1728 | { |
1708 | } | 1729 | newChild.UpdateFlag = 0; |
1730 | linkIDs.Add(newChild.LocalId); | ||
1731 | } | ||
1709 | 1732 | ||
1710 | LinkObjects(null, newRoot.LocalId, linkIDs); | 1733 | LinkObjects(null, newRoot.LocalId, linkIDs); |
1711 | if (!affectedGroups.Contains(newRoot.ParentGroup)) | 1734 | if (!affectedGroups.Contains(newRoot.ParentGroup)) |
1712 | affectedGroups.Add(newRoot.ParentGroup); | 1735 | affectedGroups.Add(newRoot.ParentGroup); |
1736 | } | ||
1713 | } | 1737 | } |
1714 | } | 1738 | } |
1715 | } | ||
1716 | 1739 | ||
1717 | // Finally, trigger events in the roots | 1740 | // Finally, trigger events in the roots |
1718 | // | 1741 | // |
1719 | foreach (SceneObjectGroup g in affectedGroups) | 1742 | foreach (SceneObjectGroup g in affectedGroups) |
1743 | { | ||
1744 | g.TriggerScriptChangedEvent(Changed.LINK); | ||
1745 | g.HasGroupChanged = true; // Persist | ||
1746 | g.ScheduleGroupForFullUpdate(); | ||
1747 | } | ||
1748 | } | ||
1749 | finally | ||
1720 | { | 1750 | { |
1721 | g.TriggerScriptChangedEvent(Changed.LINK); | 1751 | Monitor.Exit(m_updateLock); |
1722 | g.HasGroupChanged = true; // Persist | ||
1723 | g.ScheduleGroupForFullUpdate(); | ||
1724 | } | 1752 | } |
1725 | } | 1753 | } |
1726 | 1754 | ||