diff options
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 164 |
1 files changed, 89 insertions, 75 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 67eb0fe..4815922 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -92,8 +92,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
92 | protected internal Dictionary<uint, SceneObjectGroup> SceneObjectGroupsByLocalPartID = new Dictionary<uint, SceneObjectGroup>(); | 92 | protected internal Dictionary<uint, SceneObjectGroup> SceneObjectGroupsByLocalPartID = new Dictionary<uint, SceneObjectGroup>(); |
93 | 93 | ||
94 | /// <summary> | 94 | /// <summary> |
95 | /// Lock to prevent object group update, linking and delinking operations from running concurrently. | 95 | /// Lock to prevent object group update, linking, delinking and duplication operations from running concurrently. |
96 | /// </summary> | 96 | /// </summary> |
97 | /// <remarks> | ||
98 | /// These operations rely on the parts composition of the object. If allowed to run concurrently then race | ||
99 | /// conditions can occur. | ||
100 | /// </remarks> | ||
97 | private Object m_updateLock = new Object(); | 101 | private Object m_updateLock = new Object(); |
98 | 102 | ||
99 | #endregion | 103 | #endregion |
@@ -1844,96 +1848,106 @@ namespace OpenSim.Region.Framework.Scenes | |||
1844 | /// <param name="AgentID"></param> | 1848 | /// <param name="AgentID"></param> |
1845 | /// <param name="GroupID"></param> | 1849 | /// <param name="GroupID"></param> |
1846 | /// <param name="rot"></param> | 1850 | /// <param name="rot"></param> |
1847 | public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) | 1851 | /// <returns>null if duplication fails, otherwise the duplicated object</returns> |
1852 | public SceneObjectGroup DuplicateObject( | ||
1853 | uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) | ||
1848 | { | 1854 | { |
1849 | // m_log.DebugFormat( | 1855 | Monitor.Enter(m_updateLock); |
1850 | // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", | 1856 | |
1851 | // originalPrimID, offset, AgentID); | 1857 | try |
1852 | |||
1853 | SceneObjectGroup original = GetGroupByPrim(originalPrimID); | ||
1854 | if (original != null) | ||
1855 | { | 1858 | { |
1856 | if (m_parentScene.Permissions.CanDuplicateObject( | 1859 | // m_log.DebugFormat( |
1857 | original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) | 1860 | // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", |
1861 | // originalPrimID, offset, AgentID); | ||
1862 | |||
1863 | SceneObjectGroup original = GetGroupByPrim(originalPrimID); | ||
1864 | if (original == null) | ||
1858 | { | 1865 | { |
1859 | SceneObjectGroup copy = original.Copy(true); | 1866 | m_log.WarnFormat( |
1860 | copy.AbsolutePosition = copy.AbsolutePosition + offset; | 1867 | "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); |
1861 | 1868 | ||
1862 | if (original.OwnerID != AgentID) | 1869 | return null; |
1863 | { | 1870 | } |
1864 | copy.SetOwnerId(AgentID); | ||
1865 | copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID); | ||
1866 | 1871 | ||
1867 | SceneObjectPart[] partList = copy.Parts; | 1872 | if (!m_parentScene.Permissions.CanDuplicateObject( |
1873 | original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) | ||
1874 | return null; | ||
1868 | 1875 | ||
1869 | if (m_parentScene.Permissions.PropagatePermissions()) | 1876 | SceneObjectGroup copy = original.Copy(true); |
1870 | { | 1877 | copy.AbsolutePosition = copy.AbsolutePosition + offset; |
1871 | foreach (SceneObjectPart child in partList) | ||
1872 | { | ||
1873 | child.Inventory.ChangeInventoryOwner(AgentID); | ||
1874 | child.TriggerScriptChangedEvent(Changed.OWNER); | ||
1875 | child.ApplyNextOwnerPermissions(); | ||
1876 | } | ||
1877 | } | ||
1878 | 1878 | ||
1879 | copy.RootPart.ObjectSaleType = 0; | 1879 | if (original.OwnerID != AgentID) |
1880 | copy.RootPart.SalePrice = 10; | 1880 | { |
1881 | } | 1881 | copy.SetOwnerId(AgentID); |
1882 | copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID); | ||
1882 | 1883 | ||
1883 | // FIXME: This section needs to be refactored so that it just calls AddSceneObject() | 1884 | SceneObjectPart[] partList = copy.Parts; |
1884 | Entities.Add(copy); | 1885 | |
1885 | 1886 | if (m_parentScene.Permissions.PropagatePermissions()) | |
1886 | lock (SceneObjectGroupsByFullID) | ||
1887 | SceneObjectGroupsByFullID[copy.UUID] = copy; | ||
1888 | |||
1889 | SceneObjectPart[] children = copy.Parts; | ||
1890 | |||
1891 | lock (SceneObjectGroupsByFullPartID) | ||
1892 | { | ||
1893 | SceneObjectGroupsByFullPartID[copy.UUID] = copy; | ||
1894 | foreach (SceneObjectPart part in children) | ||
1895 | SceneObjectGroupsByFullPartID[part.UUID] = copy; | ||
1896 | } | ||
1897 | |||
1898 | lock (SceneObjectGroupsByLocalPartID) | ||
1899 | { | ||
1900 | SceneObjectGroupsByLocalPartID[copy.LocalId] = copy; | ||
1901 | foreach (SceneObjectPart part in children) | ||
1902 | SceneObjectGroupsByLocalPartID[part.LocalId] = copy; | ||
1903 | } | ||
1904 | // PROBABLE END OF FIXME | ||
1905 | |||
1906 | // Since we copy from a source group that is in selected | ||
1907 | // state, but the copy is shown deselected in the viewer, | ||
1908 | // We need to clear the selection flag here, else that | ||
1909 | // prim never gets persisted at all. The client doesn't | ||
1910 | // think it's selected, so it will never send a deselect... | ||
1911 | copy.IsSelected = false; | ||
1912 | |||
1913 | m_numPrim += copy.Parts.Length; | ||
1914 | |||
1915 | if (rot != Quaternion.Identity) | ||
1916 | { | 1887 | { |
1917 | copy.UpdateGroupRotationR(rot); | 1888 | foreach (SceneObjectPart child in partList) |
1889 | { | ||
1890 | child.Inventory.ChangeInventoryOwner(AgentID); | ||
1891 | child.TriggerScriptChangedEvent(Changed.OWNER); | ||
1892 | child.ApplyNextOwnerPermissions(); | ||
1893 | } | ||
1918 | } | 1894 | } |
1919 | 1895 | ||
1920 | copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); | 1896 | copy.RootPart.ObjectSaleType = 0; |
1921 | copy.HasGroupChanged = true; | 1897 | copy.RootPart.SalePrice = 10; |
1922 | copy.ScheduleGroupForFullUpdate(); | 1898 | } |
1923 | copy.ResumeScripts(); | ||
1924 | |||
1925 | // required for physics to update it's position | ||
1926 | copy.AbsolutePosition = copy.AbsolutePosition; | ||
1927 | 1899 | ||
1928 | return copy; | 1900 | // FIXME: This section needs to be refactored so that it just calls AddSceneObject() |
1901 | Entities.Add(copy); | ||
1902 | |||
1903 | lock (SceneObjectGroupsByFullID) | ||
1904 | SceneObjectGroupsByFullID[copy.UUID] = copy; | ||
1905 | |||
1906 | SceneObjectPart[] children = copy.Parts; | ||
1907 | |||
1908 | lock (SceneObjectGroupsByFullPartID) | ||
1909 | { | ||
1910 | SceneObjectGroupsByFullPartID[copy.UUID] = copy; | ||
1911 | foreach (SceneObjectPart part in children) | ||
1912 | SceneObjectGroupsByFullPartID[part.UUID] = copy; | ||
1913 | } | ||
1914 | |||
1915 | lock (SceneObjectGroupsByLocalPartID) | ||
1916 | { | ||
1917 | SceneObjectGroupsByLocalPartID[copy.LocalId] = copy; | ||
1918 | foreach (SceneObjectPart part in children) | ||
1919 | SceneObjectGroupsByLocalPartID[part.LocalId] = copy; | ||
1920 | } | ||
1921 | // PROBABLE END OF FIXME | ||
1922 | |||
1923 | // Since we copy from a source group that is in selected | ||
1924 | // state, but the copy is shown deselected in the viewer, | ||
1925 | // We need to clear the selection flag here, else that | ||
1926 | // prim never gets persisted at all. The client doesn't | ||
1927 | // think it's selected, so it will never send a deselect... | ||
1928 | copy.IsSelected = false; | ||
1929 | |||
1930 | m_numPrim += copy.Parts.Length; | ||
1931 | |||
1932 | if (rot != Quaternion.Identity) | ||
1933 | { | ||
1934 | copy.UpdateGroupRotationR(rot); | ||
1929 | } | 1935 | } |
1936 | |||
1937 | copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); | ||
1938 | copy.HasGroupChanged = true; | ||
1939 | copy.ScheduleGroupForFullUpdate(); | ||
1940 | copy.ResumeScripts(); | ||
1941 | |||
1942 | // required for physics to update it's position | ||
1943 | copy.AbsolutePosition = copy.AbsolutePosition; | ||
1944 | |||
1945 | return copy; | ||
1930 | } | 1946 | } |
1931 | else | 1947 | finally |
1932 | { | 1948 | { |
1933 | m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID); | 1949 | Monitor.Exit(m_updateLock); |
1934 | } | 1950 | } |
1935 | |||
1936 | return null; | ||
1937 | } | 1951 | } |
1938 | 1952 | ||
1939 | /// <summary> | 1953 | /// <summary> |