aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneGraph.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs479
1 files changed, 345 insertions, 134 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 4815922..00f76e0 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -41,6 +41,12 @@ namespace OpenSim.Region.Framework.Scenes
41{ 41{
42 public delegate void PhysicsCrash(); 42 public delegate void PhysicsCrash();
43 43
44 public delegate void AttachToBackupDelegate(SceneObjectGroup sog);
45
46 public delegate void DetachFromBackupDelegate(SceneObjectGroup sog);
47
48 public delegate void ChangedBackupDelegate(SceneObjectGroup sog);
49
44 /// <summary> 50 /// <summary>
45 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components 51 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
46 /// should be migrated out over time. 52 /// should be migrated out over time.
@@ -54,11 +60,15 @@ namespace OpenSim.Region.Framework.Scenes
54 protected internal event PhysicsCrash UnRecoverableError; 60 protected internal event PhysicsCrash UnRecoverableError;
55 private PhysicsCrash handlerPhysicsCrash = null; 61 private PhysicsCrash handlerPhysicsCrash = null;
56 62
63 public event AttachToBackupDelegate OnAttachToBackup;
64 public event DetachFromBackupDelegate OnDetachFromBackup;
65 public event ChangedBackupDelegate OnChangeBackup;
66
57 #endregion 67 #endregion
58 68
59 #region Fields 69 #region Fields
60 70
61 protected object m_presenceLock = new object(); 71 protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
62 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>(); 72 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
63 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>(); 73 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
64 74
@@ -127,13 +137,18 @@ namespace OpenSim.Region.Framework.Scenes
127 137
128 protected internal void Close() 138 protected internal void Close()
129 { 139 {
130 lock (m_presenceLock) 140 m_scenePresencesLock.EnterWriteLock();
141 try
131 { 142 {
132 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); 143 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
133 List<ScenePresence> newlist = new List<ScenePresence>(); 144 List<ScenePresence> newlist = new List<ScenePresence>();
134 m_scenePresenceMap = newmap; 145 m_scenePresenceMap = newmap;
135 m_scenePresenceArray = newlist; 146 m_scenePresenceArray = newlist;
136 } 147 }
148 finally
149 {
150 m_scenePresencesLock.ExitWriteLock();
151 }
137 152
138 lock (SceneObjectGroupsByFullID) 153 lock (SceneObjectGroupsByFullID)
139 SceneObjectGroupsByFullID.Clear(); 154 SceneObjectGroupsByFullID.Clear();
@@ -254,6 +269,33 @@ namespace OpenSim.Region.Framework.Scenes
254 protected internal bool AddRestoredSceneObject( 269 protected internal bool AddRestoredSceneObject(
255 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 270 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
256 { 271 {
272 if (!m_parentScene.CombineRegions)
273 {
274 // KF: Check for out-of-region, move inside and make static.
275 Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X,
276 sceneObject.RootPart.GroupPosition.Y,
277 sceneObject.RootPart.GroupPosition.Z);
278 if (!(((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0))) && (npos.X < 0.0 || npos.Y < 0.0 || npos.Z < 0.0 ||
279 npos.X > Constants.RegionSize ||
280 npos.Y > Constants.RegionSize))
281 {
282 if (npos.X < 0.0) npos.X = 1.0f;
283 if (npos.Y < 0.0) npos.Y = 1.0f;
284 if (npos.Z < 0.0) npos.Z = 0.0f;
285 if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f;
286 if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f;
287
288 foreach (SceneObjectPart part in sceneObject.Parts)
289 {
290 part.GroupPosition = npos;
291 }
292 sceneObject.RootPart.Velocity = Vector3.Zero;
293 sceneObject.RootPart.AngularVelocity = Vector3.Zero;
294 sceneObject.RootPart.Acceleration = Vector3.Zero;
295 sceneObject.RootPart.Velocity = Vector3.Zero;
296 }
297 }
298
257 if (attachToBackup && (!alreadyPersisted)) 299 if (attachToBackup && (!alreadyPersisted))
258 { 300 {
259 sceneObject.ForceInventoryPersistence(); 301 sceneObject.ForceInventoryPersistence();
@@ -319,7 +361,7 @@ namespace OpenSim.Region.Framework.Scenes
319 sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false); 361 sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false);
320 sceneObject.Velocity = vel; 362 sceneObject.Velocity = vel;
321 } 363 }
322 364
323 return true; 365 return true;
324 } 366 }
325 367
@@ -344,6 +386,11 @@ namespace OpenSim.Region.Framework.Scenes
344 /// </returns> 386 /// </returns>
345 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) 387 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
346 { 388 {
389 if (sceneObject == null)
390 {
391 m_log.ErrorFormat("[SCENEGRAPH]: Tried to add null scene object");
392 return false;
393 }
347 if (sceneObject.UUID == UUID.Zero) 394 if (sceneObject.UUID == UUID.Zero)
348 { 395 {
349 m_log.ErrorFormat( 396 m_log.ErrorFormat(
@@ -478,6 +525,30 @@ namespace OpenSim.Region.Framework.Scenes
478 m_updateList[obj.UUID] = obj; 525 m_updateList[obj.UUID] = obj;
479 } 526 }
480 527
528 public void FireAttachToBackup(SceneObjectGroup obj)
529 {
530 if (OnAttachToBackup != null)
531 {
532 OnAttachToBackup(obj);
533 }
534 }
535
536 public void FireDetachFromBackup(SceneObjectGroup obj)
537 {
538 if (OnDetachFromBackup != null)
539 {
540 OnDetachFromBackup(obj);
541 }
542 }
543
544 public void FireChangeBackup(SceneObjectGroup obj)
545 {
546 if (OnChangeBackup != null)
547 {
548 OnChangeBackup(obj);
549 }
550 }
551
481 /// <summary> 552 /// <summary>
482 /// Process all pending updates 553 /// Process all pending updates
483 /// </summary> 554 /// </summary>
@@ -595,7 +666,8 @@ namespace OpenSim.Region.Framework.Scenes
595 666
596 Entities[presence.UUID] = presence; 667 Entities[presence.UUID] = presence;
597 668
598 lock (m_presenceLock) 669 m_scenePresencesLock.EnterWriteLock();
670 try
599 { 671 {
600 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 672 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
601 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 673 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -619,6 +691,10 @@ namespace OpenSim.Region.Framework.Scenes
619 m_scenePresenceMap = newmap; 691 m_scenePresenceMap = newmap;
620 m_scenePresenceArray = newlist; 692 m_scenePresenceArray = newlist;
621 } 693 }
694 finally
695 {
696 m_scenePresencesLock.ExitWriteLock();
697 }
622 } 698 }
623 699
624 /// <summary> 700 /// <summary>
@@ -633,7 +709,8 @@ namespace OpenSim.Region.Framework.Scenes
633 agentID); 709 agentID);
634 } 710 }
635 711
636 lock (m_presenceLock) 712 m_scenePresencesLock.EnterWriteLock();
713 try
637 { 714 {
638 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 715 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
639 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 716 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -655,6 +732,10 @@ namespace OpenSim.Region.Framework.Scenes
655 m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); 732 m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
656 } 733 }
657 } 734 }
735 finally
736 {
737 m_scenePresencesLock.ExitWriteLock();
738 }
658 } 739 }
659 740
660 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) 741 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
@@ -1187,6 +1268,52 @@ namespace OpenSim.Region.Framework.Scenes
1187 1268
1188 #region Client Event handlers 1269 #region Client Event handlers
1189 1270
1271 protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient)
1272 {
1273 SceneObjectPart part = GetSceneObjectPart(localID);
1274 ObjectChangeData data = (ObjectChangeData)odata;
1275
1276 if (part != null)
1277 {
1278 SceneObjectGroup grp = part.ParentGroup;
1279 if (grp != null)
1280 {
1281 if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId))
1282 {
1283 // These two are exceptions SL makes in the interpretation
1284 // of the change flags. Must check them here because otherwise
1285 // the group flag (see below) would be lost
1286 if (data.change == ObjectChangeType.groupS)
1287 data.change = ObjectChangeType.primS;
1288 if (data.change == ObjectChangeType.groupPS)
1289 data.change = ObjectChangeType.primPS;
1290 part.StoreUndoState(data.change); // lets test only saving what we changed
1291 grp.doChangeObject(part, (ObjectChangeData)data);
1292 }
1293 else
1294 {
1295 // Is this any kind of group operation?
1296 if ((data.change & ObjectChangeType.Group) != 0)
1297 {
1298 // Is a move and/or rotation requested?
1299 if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0)
1300 {
1301 // Are we allowed to move it?
1302 if (m_parentScene.Permissions.CanMoveObject(grp.UUID, remoteClient.AgentId))
1303 {
1304 // Strip all but move and rotation from request
1305 data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation);
1306
1307 part.StoreUndoState(data.change);
1308 grp.doChangeObject(part, (ObjectChangeData)data);
1309 }
1310 }
1311 }
1312 }
1313 }
1314 }
1315 }
1316
1190 /// <summary> 1317 /// <summary>
1191 /// Update the scale of an individual prim. 1318 /// Update the scale of an individual prim.
1192 /// </summary> 1319 /// </summary>
@@ -1201,7 +1328,17 @@ namespace OpenSim.Region.Framework.Scenes
1201 { 1328 {
1202 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) 1329 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId))
1203 { 1330 {
1331 bool physbuild = false;
1332 if (part.ParentGroup.RootPart.PhysActor != null)
1333 {
1334 part.ParentGroup.RootPart.PhysActor.Building = true;
1335 physbuild = true;
1336 }
1337
1204 part.Resize(scale); 1338 part.Resize(scale);
1339
1340 if (physbuild)
1341 part.ParentGroup.RootPart.PhysActor.Building = false;
1205 } 1342 }
1206 } 1343 }
1207 } 1344 }
@@ -1213,7 +1350,17 @@ namespace OpenSim.Region.Framework.Scenes
1213 { 1350 {
1214 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1351 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1215 { 1352 {
1353 bool physbuild = false;
1354 if (group.RootPart.PhysActor != null)
1355 {
1356 group.RootPart.PhysActor.Building = true;
1357 physbuild = true;
1358 }
1359
1216 group.GroupResize(scale); 1360 group.GroupResize(scale);
1361
1362 if (physbuild)
1363 group.RootPart.PhysActor.Building = false;
1217 } 1364 }
1218 } 1365 }
1219 } 1366 }
@@ -1341,8 +1488,13 @@ namespace OpenSim.Region.Framework.Scenes
1341 { 1488 {
1342 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) 1489 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1343 { 1490 {
1344 if (m_parentScene.AttachmentsModule != null) 1491 // Set the new attachment point data in the object
1345 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); 1492 byte attachmentPoint = group.GetAttachmentPoint();
1493 group.UpdateGroupPosition(pos);
1494 group.IsAttachment = false;
1495 group.AbsolutePosition = group.RootPart.AttachedPos;
1496 group.AttachmentPoint = attachmentPoint;
1497 group.HasGroupChanged = true;
1346 } 1498 }
1347 else 1499 else
1348 { 1500 {
@@ -1390,7 +1542,7 @@ namespace OpenSim.Region.Framework.Scenes
1390 /// <param name="SetPhantom"></param> 1542 /// <param name="SetPhantom"></param>
1391 /// <param name="remoteClient"></param> 1543 /// <param name="remoteClient"></param>
1392 protected internal void UpdatePrimFlags( 1544 protected internal void UpdatePrimFlags(
1393 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) 1545 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1394 { 1546 {
1395 SceneObjectGroup group = GetGroupByPrim(localID); 1547 SceneObjectGroup group = GetGroupByPrim(localID);
1396 if (group != null) 1548 if (group != null)
@@ -1398,7 +1550,28 @@ namespace OpenSim.Region.Framework.Scenes
1398 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1550 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1399 { 1551 {
1400 // VolumeDetect can't be set via UI and will always be off when a change is made there 1552 // VolumeDetect can't be set via UI and will always be off when a change is made there
1401 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); 1553 // now only change volume dtc if phantom off
1554
1555 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1556 {
1557 bool vdtc;
1558 if (SetPhantom) // if phantom keep volumedtc
1559 vdtc = group.RootPart.VolumeDetectActive;
1560 else // else turn it off
1561 vdtc = false;
1562
1563 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1564 }
1565 else
1566 {
1567 SceneObjectPart part = GetSceneObjectPart(localID);
1568 if (part != null)
1569 {
1570 part.UpdateExtraPhysics(PhysData);
1571 if (part.UpdatePhysRequired)
1572 remoteClient.SendPartPhysicsProprieties(part);
1573 }
1574 }
1402 } 1575 }
1403 } 1576 }
1404 } 1577 }
@@ -1542,6 +1715,7 @@ namespace OpenSim.Region.Framework.Scenes
1542 { 1715 {
1543 part.Material = Convert.ToByte(material); 1716 part.Material = Convert.ToByte(material);
1544 group.HasGroupChanged = true; 1717 group.HasGroupChanged = true;
1718 remoteClient.SendPartPhysicsProprieties(part);
1545 } 1719 }
1546 } 1720 }
1547 } 1721 }
@@ -1606,6 +1780,12 @@ namespace OpenSim.Region.Framework.Scenes
1606 /// <param name="childPrims"></param> 1780 /// <param name="childPrims"></param>
1607 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1781 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1608 { 1782 {
1783 if (root.KeyframeMotion != null)
1784 {
1785 root.KeyframeMotion.Stop();
1786 root.KeyframeMotion = null;
1787 }
1788
1609 SceneObjectGroup parentGroup = root.ParentGroup; 1789 SceneObjectGroup parentGroup = root.ParentGroup;
1610 if (parentGroup == null) return; 1790 if (parentGroup == null) return;
1611 1791
@@ -1614,8 +1794,11 @@ namespace OpenSim.Region.Framework.Scenes
1614 return; 1794 return;
1615 1795
1616 Monitor.Enter(m_updateLock); 1796 Monitor.Enter(m_updateLock);
1797
1617 try 1798 try
1618 { 1799 {
1800 parentGroup.areUpdatesSuspended = true;
1801
1619 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1802 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1620 1803
1621 // We do this in reverse to get the link order of the prims correct 1804 // We do this in reverse to get the link order of the prims correct
@@ -1630,9 +1813,13 @@ namespace OpenSim.Region.Framework.Scenes
1630 // Make sure no child prim is set for sale 1813 // Make sure no child prim is set for sale
1631 // So that, on delink, no prims are unwittingly 1814 // So that, on delink, no prims are unwittingly
1632 // left for sale and sold off 1815 // left for sale and sold off
1633 child.RootPart.ObjectSaleType = 0; 1816
1634 child.RootPart.SalePrice = 10; 1817 if (child != null)
1635 childGroups.Add(child); 1818 {
1819 child.RootPart.ObjectSaleType = 0;
1820 child.RootPart.SalePrice = 10;
1821 childGroups.Add(child);
1822 }
1636 } 1823 }
1637 1824
1638 foreach (SceneObjectGroup child in childGroups) 1825 foreach (SceneObjectGroup child in childGroups)
@@ -1659,6 +1846,16 @@ namespace OpenSim.Region.Framework.Scenes
1659 } 1846 }
1660 finally 1847 finally
1661 { 1848 {
1849 lock (SceneObjectGroupsByLocalPartID)
1850 {
1851 foreach (SceneObjectPart part in parentGroup.Parts)
1852 SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
1853 }
1854
1855 parentGroup.areUpdatesSuspended = false;
1856 parentGroup.HasGroupChanged = true;
1857 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1858 parentGroup.ScheduleGroupForFullUpdate();
1662 Monitor.Exit(m_updateLock); 1859 Monitor.Exit(m_updateLock);
1663 } 1860 }
1664 } 1861 }
@@ -1681,6 +1878,11 @@ namespace OpenSim.Region.Framework.Scenes
1681 { 1878 {
1682 if (part != null) 1879 if (part != null)
1683 { 1880 {
1881 if (part.KeyframeMotion != null)
1882 {
1883 part.KeyframeMotion.Stop();
1884 part.KeyframeMotion = null;
1885 }
1684 if (part.ParentGroup.PrimCount != 1) // Skip single 1886 if (part.ParentGroup.PrimCount != 1) // Skip single
1685 { 1887 {
1686 if (part.LinkNum < 2) // Root 1888 if (part.LinkNum < 2) // Root
@@ -1695,21 +1897,24 @@ namespace OpenSim.Region.Framework.Scenes
1695 1897
1696 SceneObjectGroup group = part.ParentGroup; 1898 SceneObjectGroup group = part.ParentGroup;
1697 if (!affectedGroups.Contains(group)) 1899 if (!affectedGroups.Contains(group))
1900 {
1901 group.areUpdatesSuspended = true;
1698 affectedGroups.Add(group); 1902 affectedGroups.Add(group);
1903 }
1699 } 1904 }
1700 } 1905 }
1701 } 1906 }
1702 1907
1703 foreach (SceneObjectPart child in childParts) 1908 if (childParts.Count > 0)
1704 { 1909 {
1705 // Unlink all child parts from their groups 1910 foreach (SceneObjectPart child in childParts)
1706 // 1911 {
1707 child.ParentGroup.DelinkFromGroup(child, true); 1912 // Unlink all child parts from their groups
1708 1913 //
1709 // These are not in affected groups and will not be 1914 child.ParentGroup.DelinkFromGroup(child, true);
1710 // handled further. Do the honors here. 1915 child.ParentGroup.HasGroupChanged = true;
1711 child.ParentGroup.HasGroupChanged = true; 1916 child.ParentGroup.ScheduleGroupForFullUpdate();
1712 child.ParentGroup.ScheduleGroupForFullUpdate(); 1917 }
1713 } 1918 }
1714 1919
1715 foreach (SceneObjectPart root in rootParts) 1920 foreach (SceneObjectPart root in rootParts)
@@ -1719,56 +1924,68 @@ namespace OpenSim.Region.Framework.Scenes
1719 // However, editing linked parts and unlinking may be different 1924 // However, editing linked parts and unlinking may be different
1720 // 1925 //
1721 SceneObjectGroup group = root.ParentGroup; 1926 SceneObjectGroup group = root.ParentGroup;
1927 group.areUpdatesSuspended = true;
1722 1928
1723 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1929 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1724 int numChildren = newSet.Count; 1930 int numChildren = newSet.Count;
1725 1931
1932 if (numChildren == 1)
1933 break;
1934
1726 // If there are prims left in a link set, but the root is 1935 // If there are prims left in a link set, but the root is
1727 // slated for unlink, we need to do this 1936 // slated for unlink, we need to do this
1937 // Unlink the remaining set
1728 // 1938 //
1729 if (numChildren != 1) 1939 bool sendEventsToRemainder = true;
1730 { 1940 if (numChildren > 1)
1731 // Unlink the remaining set 1941 sendEventsToRemainder = false;
1732 //
1733 bool sendEventsToRemainder = true;
1734 if (numChildren > 1)
1735 sendEventsToRemainder = false;
1736 1942
1737 foreach (SceneObjectPart p in newSet) 1943 foreach (SceneObjectPart p in newSet)
1944 {
1945 if (p != group.RootPart)
1738 { 1946 {
1739 if (p != group.RootPart) 1947 group.DelinkFromGroup(p, sendEventsToRemainder);
1740 group.DelinkFromGroup(p, sendEventsToRemainder); 1948 if (numChildren > 2)
1949 {
1950 p.ParentGroup.areUpdatesSuspended = true;
1951 }
1952 else
1953 {
1954 p.ParentGroup.HasGroupChanged = true;
1955 p.ParentGroup.ScheduleGroupForFullUpdate();
1956 }
1741 } 1957 }
1958 }
1959
1960 // If there is more than one prim remaining, we
1961 // need to re-link
1962 //
1963 if (numChildren > 2)
1964 {
1965 // Remove old root
1966 //
1967 if (newSet.Contains(root))
1968 newSet.Remove(root);
1742 1969
1743 // If there is more than one prim remaining, we 1970 // Preserve link ordering
1744 // need to re-link
1745 // 1971 //
1746 if (numChildren > 2) 1972 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1747 { 1973 {
1748 // Remove old root 1974 return a.LinkNum.CompareTo(b.LinkNum);
1749 // 1975 });
1750 if (newSet.Contains(root))
1751 newSet.Remove(root);
1752
1753 // Preserve link ordering
1754 //
1755 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1756 {
1757 return a.LinkNum.CompareTo(b.LinkNum);
1758 });
1759 1976
1760 // Determine new root 1977 // Determine new root
1761 // 1978 //
1762 SceneObjectPart newRoot = newSet[0]; 1979 SceneObjectPart newRoot = newSet[0];
1763 newSet.RemoveAt(0); 1980 newSet.RemoveAt(0);
1764 1981
1765 foreach (SceneObjectPart newChild in newSet) 1982 foreach (SceneObjectPart newChild in newSet)
1766 newChild.ClearUpdateSchedule(); 1983 newChild.ClearUpdateSchedule();
1767 1984
1768 LinkObjects(newRoot, newSet); 1985 newRoot.ParentGroup.areUpdatesSuspended = true;
1769 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1986 LinkObjects(newRoot, newSet);
1770 affectedGroups.Add(newRoot.ParentGroup); 1987 if (!affectedGroups.Contains(newRoot.ParentGroup))
1771 } 1988 affectedGroups.Add(newRoot.ParentGroup);
1772 } 1989 }
1773 } 1990 }
1774 1991
@@ -1776,8 +1993,14 @@ namespace OpenSim.Region.Framework.Scenes
1776 // 1993 //
1777 foreach (SceneObjectGroup g in affectedGroups) 1994 foreach (SceneObjectGroup g in affectedGroups)
1778 { 1995 {
1996 // Child prims that have been unlinked and deleted will
1997 // return unless the root is deleted. This will remove them
1998 // from the database. They will be rewritten immediately,
1999 // minus the rows for the unlinked child prims.
2000 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1779 g.TriggerScriptChangedEvent(Changed.LINK); 2001 g.TriggerScriptChangedEvent(Changed.LINK);
1780 g.HasGroupChanged = true; // Persist 2002 g.HasGroupChanged = true; // Persist
2003 g.areUpdatesSuspended = false;
1781 g.ScheduleGroupForFullUpdate(); 2004 g.ScheduleGroupForFullUpdate();
1782 } 2005 }
1783 } 2006 }
@@ -1849,108 +2072,96 @@ namespace OpenSim.Region.Framework.Scenes
1849 /// <param name="GroupID"></param> 2072 /// <param name="GroupID"></param>
1850 /// <param name="rot"></param> 2073 /// <param name="rot"></param>
1851 /// <returns>null if duplication fails, otherwise the duplicated object</returns> 2074 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1852 public SceneObjectGroup DuplicateObject( 2075 /// <summary>
1853 uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) 2076 public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1854 { 2077 {
1855 Monitor.Enter(m_updateLock); 2078// m_log.DebugFormat(
2079// "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
2080// originalPrimID, offset, AgentID);
1856 2081
1857 try 2082 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
2083 if (original != null)
1858 { 2084 {
1859 // m_log.DebugFormat( 2085 if (m_parentScene.Permissions.CanDuplicateObject(
1860 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", 2086 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1861 // originalPrimID, offset, AgentID);
1862
1863 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1864 if (original == null)
1865 { 2087 {
1866 m_log.WarnFormat( 2088 SceneObjectGroup copy = original.Copy(true);
1867 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); 2089 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1868 2090
1869 return null; 2091 if (original.OwnerID != AgentID)
1870 } 2092 {
2093 copy.SetOwnerId(AgentID);
2094 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1871 2095
1872 if (!m_parentScene.Permissions.CanDuplicateObject( 2096 SceneObjectPart[] partList = copy.Parts;
1873 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1874 return null;
1875 2097
1876 SceneObjectGroup copy = original.Copy(true); 2098 if (m_parentScene.Permissions.PropagatePermissions())
1877 copy.AbsolutePosition = copy.AbsolutePosition + offset; 2099 {
2100 foreach (SceneObjectPart child in partList)
2101 {
2102 child.Inventory.ChangeInventoryOwner(AgentID);
2103 child.TriggerScriptChangedEvent(Changed.OWNER);
2104 child.ApplyNextOwnerPermissions();
2105 }
2106 }
2107 }
1878 2108
1879 if (original.OwnerID != AgentID) 2109 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1880 { 2110 Entities.Add(copy);
1881 copy.SetOwnerId(AgentID);
1882 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1883 2111
1884 SceneObjectPart[] partList = copy.Parts; 2112 lock (SceneObjectGroupsByFullID)
2113 SceneObjectGroupsByFullID[copy.UUID] = copy;
1885 2114
1886 if (m_parentScene.Permissions.PropagatePermissions()) 2115 SceneObjectPart[] children = copy.Parts;
2116
2117 lock (SceneObjectGroupsByFullPartID)
1887 { 2118 {
1888 foreach (SceneObjectPart child in partList) 2119 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1889 { 2120 foreach (SceneObjectPart part in children)
1890 child.Inventory.ChangeInventoryOwner(AgentID); 2121 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1891 child.TriggerScriptChangedEvent(Changed.OWNER);
1892 child.ApplyNextOwnerPermissions();
1893 }
1894 } 2122 }
1895 2123
1896 copy.RootPart.ObjectSaleType = 0; 2124 lock (SceneObjectGroupsByLocalPartID)
1897 copy.RootPart.SalePrice = 10; 2125 {
1898 } 2126 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
2127 foreach (SceneObjectPart part in children)
2128 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
2129 }
2130 // PROBABLE END OF FIXME
1899 2131
1900 // FIXME: This section needs to be refactored so that it just calls AddSceneObject() 2132 // Since we copy from a source group that is in selected
1901 Entities.Add(copy); 2133 // state, but the copy is shown deselected in the viewer,
1902 2134 // We need to clear the selection flag here, else that
1903 lock (SceneObjectGroupsByFullID) 2135 // prim never gets persisted at all. The client doesn't
1904 SceneObjectGroupsByFullID[copy.UUID] = copy; 2136 // think it's selected, so it will never send a deselect...
1905 2137 copy.IsSelected = false;
1906 SceneObjectPart[] children = copy.Parts; 2138
1907 2139 m_numPrim += copy.Parts.Length;
1908 lock (SceneObjectGroupsByFullPartID) 2140
1909 { 2141 if (rot != Quaternion.Identity)
1910 SceneObjectGroupsByFullPartID[copy.UUID] = copy; 2142 {
1911 foreach (SceneObjectPart part in children) 2143 copy.UpdateGroupRotationR(rot);
1912 SceneObjectGroupsByFullPartID[part.UUID] = copy; 2144 }
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);
1935 }
1936 2145
1937 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); 2146 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1938 copy.HasGroupChanged = true; 2147 copy.HasGroupChanged = true;
1939 copy.ScheduleGroupForFullUpdate(); 2148 copy.ScheduleGroupForFullUpdate();
1940 copy.ResumeScripts(); 2149 copy.ResumeScripts();
1941 2150
1942 // required for physics to update it's position 2151 // required for physics to update it's position
1943 copy.AbsolutePosition = copy.AbsolutePosition; 2152 copy.AbsolutePosition = copy.AbsolutePosition;
1944 2153
1945 return copy; 2154 return copy;
2155 }
1946 } 2156 }
1947 finally 2157 else
1948 { 2158 {
1949 Monitor.Exit(m_updateLock); 2159 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1950 } 2160 }
2161
2162 return null;
1951 } 2163 }
1952 2164
1953 /// <summary>
1954 /// Calculates the distance between two Vector3s 2165 /// Calculates the distance between two Vector3s
1955 /// </summary> 2166 /// </summary>
1956 /// <param name="v1"></param> 2167 /// <param name="v1"></param>