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 ddf1550..23a0550 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)
@@ -1182,6 +1263,52 @@ namespace OpenSim.Region.Framework.Scenes
1182 1263
1183 #region Client Event handlers 1264 #region Client Event handlers
1184 1265
1266 protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient)
1267 {
1268 SceneObjectPart part = GetSceneObjectPart(localID);
1269 ObjectChangeData data = (ObjectChangeData)odata;
1270
1271 if (part != null)
1272 {
1273 SceneObjectGroup grp = part.ParentGroup;
1274 if (grp != null)
1275 {
1276 if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId))
1277 {
1278 // These two are exceptions SL makes in the interpretation
1279 // of the change flags. Must check them here because otherwise
1280 // the group flag (see below) would be lost
1281 if (data.change == ObjectChangeType.groupS)
1282 data.change = ObjectChangeType.primS;
1283 if (data.change == ObjectChangeType.groupPS)
1284 data.change = ObjectChangeType.primPS;
1285 part.StoreUndoState(data.change); // lets test only saving what we changed
1286 grp.doChangeObject(part, (ObjectChangeData)data);
1287 }
1288 else
1289 {
1290 // Is this any kind of group operation?
1291 if ((data.change & ObjectChangeType.Group) != 0)
1292 {
1293 // Is a move and/or rotation requested?
1294 if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0)
1295 {
1296 // Are we allowed to move it?
1297 if (m_parentScene.Permissions.CanMoveObject(grp.UUID, remoteClient.AgentId))
1298 {
1299 // Strip all but move and rotation from request
1300 data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation);
1301
1302 part.StoreUndoState(data.change);
1303 grp.doChangeObject(part, (ObjectChangeData)data);
1304 }
1305 }
1306 }
1307 }
1308 }
1309 }
1310 }
1311
1185 /// <summary> 1312 /// <summary>
1186 /// Update the scale of an individual prim. 1313 /// Update the scale of an individual prim.
1187 /// </summary> 1314 /// </summary>
@@ -1196,7 +1323,17 @@ namespace OpenSim.Region.Framework.Scenes
1196 { 1323 {
1197 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) 1324 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId))
1198 { 1325 {
1326 bool physbuild = false;
1327 if (part.ParentGroup.RootPart.PhysActor != null)
1328 {
1329 part.ParentGroup.RootPart.PhysActor.Building = true;
1330 physbuild = true;
1331 }
1332
1199 part.Resize(scale); 1333 part.Resize(scale);
1334
1335 if (physbuild)
1336 part.ParentGroup.RootPart.PhysActor.Building = false;
1200 } 1337 }
1201 } 1338 }
1202 } 1339 }
@@ -1208,7 +1345,17 @@ namespace OpenSim.Region.Framework.Scenes
1208 { 1345 {
1209 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1346 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1210 { 1347 {
1348 bool physbuild = false;
1349 if (group.RootPart.PhysActor != null)
1350 {
1351 group.RootPart.PhysActor.Building = true;
1352 physbuild = true;
1353 }
1354
1211 group.GroupResize(scale); 1355 group.GroupResize(scale);
1356
1357 if (physbuild)
1358 group.RootPart.PhysActor.Building = false;
1212 } 1359 }
1213 } 1360 }
1214 } 1361 }
@@ -1336,8 +1483,13 @@ namespace OpenSim.Region.Framework.Scenes
1336 { 1483 {
1337 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) 1484 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1338 { 1485 {
1339 if (m_parentScene.AttachmentsModule != null) 1486 // Set the new attachment point data in the object
1340 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); 1487 byte attachmentPoint = group.GetAttachmentPoint();
1488 group.UpdateGroupPosition(pos);
1489 group.IsAttachment = false;
1490 group.AbsolutePosition = group.RootPart.AttachedPos;
1491 group.AttachmentPoint = attachmentPoint;
1492 group.HasGroupChanged = true;
1341 } 1493 }
1342 else 1494 else
1343 { 1495 {
@@ -1385,7 +1537,7 @@ namespace OpenSim.Region.Framework.Scenes
1385 /// <param name="SetPhantom"></param> 1537 /// <param name="SetPhantom"></param>
1386 /// <param name="remoteClient"></param> 1538 /// <param name="remoteClient"></param>
1387 protected internal void UpdatePrimFlags( 1539 protected internal void UpdatePrimFlags(
1388 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) 1540 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1389 { 1541 {
1390 SceneObjectGroup group = GetGroupByPrim(localID); 1542 SceneObjectGroup group = GetGroupByPrim(localID);
1391 if (group != null) 1543 if (group != null)
@@ -1393,7 +1545,28 @@ namespace OpenSim.Region.Framework.Scenes
1393 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1545 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1394 { 1546 {
1395 // VolumeDetect can't be set via UI and will always be off when a change is made there 1547 // VolumeDetect can't be set via UI and will always be off when a change is made there
1396 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); 1548 // now only change volume dtc if phantom off
1549
1550 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1551 {
1552 bool vdtc;
1553 if (SetPhantom) // if phantom keep volumedtc
1554 vdtc = group.RootPart.VolumeDetectActive;
1555 else // else turn it off
1556 vdtc = false;
1557
1558 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1559 }
1560 else
1561 {
1562 SceneObjectPart part = GetSceneObjectPart(localID);
1563 if (part != null)
1564 {
1565 part.UpdateExtraPhysics(PhysData);
1566 if (part.UpdatePhysRequired)
1567 remoteClient.SendPartPhysicsProprieties(part);
1568 }
1569 }
1397 } 1570 }
1398 } 1571 }
1399 } 1572 }
@@ -1537,6 +1710,7 @@ namespace OpenSim.Region.Framework.Scenes
1537 { 1710 {
1538 part.Material = Convert.ToByte(material); 1711 part.Material = Convert.ToByte(material);
1539 group.HasGroupChanged = true; 1712 group.HasGroupChanged = true;
1713 remoteClient.SendPartPhysicsProprieties(part);
1540 } 1714 }
1541 } 1715 }
1542 } 1716 }
@@ -1601,6 +1775,12 @@ namespace OpenSim.Region.Framework.Scenes
1601 /// <param name="childPrims"></param> 1775 /// <param name="childPrims"></param>
1602 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1776 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1603 { 1777 {
1778 if (root.KeyframeMotion != null)
1779 {
1780 root.KeyframeMotion.Stop();
1781 root.KeyframeMotion = null;
1782 }
1783
1604 SceneObjectGroup parentGroup = root.ParentGroup; 1784 SceneObjectGroup parentGroup = root.ParentGroup;
1605 if (parentGroup == null) return; 1785 if (parentGroup == null) return;
1606 1786
@@ -1609,8 +1789,11 @@ namespace OpenSim.Region.Framework.Scenes
1609 return; 1789 return;
1610 1790
1611 Monitor.Enter(m_updateLock); 1791 Monitor.Enter(m_updateLock);
1792
1612 try 1793 try
1613 { 1794 {
1795 parentGroup.areUpdatesSuspended = true;
1796
1614 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1797 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1615 1798
1616 // We do this in reverse to get the link order of the prims correct 1799 // We do this in reverse to get the link order of the prims correct
@@ -1625,9 +1808,13 @@ namespace OpenSim.Region.Framework.Scenes
1625 // Make sure no child prim is set for sale 1808 // Make sure no child prim is set for sale
1626 // So that, on delink, no prims are unwittingly 1809 // So that, on delink, no prims are unwittingly
1627 // left for sale and sold off 1810 // left for sale and sold off
1628 child.RootPart.ObjectSaleType = 0; 1811
1629 child.RootPart.SalePrice = 10; 1812 if (child != null)
1630 childGroups.Add(child); 1813 {
1814 child.RootPart.ObjectSaleType = 0;
1815 child.RootPart.SalePrice = 10;
1816 childGroups.Add(child);
1817 }
1631 } 1818 }
1632 1819
1633 foreach (SceneObjectGroup child in childGroups) 1820 foreach (SceneObjectGroup child in childGroups)
@@ -1654,6 +1841,16 @@ namespace OpenSim.Region.Framework.Scenes
1654 } 1841 }
1655 finally 1842 finally
1656 { 1843 {
1844 lock (SceneObjectGroupsByLocalPartID)
1845 {
1846 foreach (SceneObjectPart part in parentGroup.Parts)
1847 SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
1848 }
1849
1850 parentGroup.areUpdatesSuspended = false;
1851 parentGroup.HasGroupChanged = true;
1852 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1853 parentGroup.ScheduleGroupForFullUpdate();
1657 Monitor.Exit(m_updateLock); 1854 Monitor.Exit(m_updateLock);
1658 } 1855 }
1659 } 1856 }
@@ -1676,6 +1873,11 @@ namespace OpenSim.Region.Framework.Scenes
1676 { 1873 {
1677 if (part != null) 1874 if (part != null)
1678 { 1875 {
1876 if (part.KeyframeMotion != null)
1877 {
1878 part.KeyframeMotion.Stop();
1879 part.KeyframeMotion = null;
1880 }
1679 if (part.ParentGroup.PrimCount != 1) // Skip single 1881 if (part.ParentGroup.PrimCount != 1) // Skip single
1680 { 1882 {
1681 if (part.LinkNum < 2) // Root 1883 if (part.LinkNum < 2) // Root
@@ -1690,21 +1892,24 @@ namespace OpenSim.Region.Framework.Scenes
1690 1892
1691 SceneObjectGroup group = part.ParentGroup; 1893 SceneObjectGroup group = part.ParentGroup;
1692 if (!affectedGroups.Contains(group)) 1894 if (!affectedGroups.Contains(group))
1895 {
1896 group.areUpdatesSuspended = true;
1693 affectedGroups.Add(group); 1897 affectedGroups.Add(group);
1898 }
1694 } 1899 }
1695 } 1900 }
1696 } 1901 }
1697 1902
1698 foreach (SceneObjectPart child in childParts) 1903 if (childParts.Count > 0)
1699 { 1904 {
1700 // Unlink all child parts from their groups 1905 foreach (SceneObjectPart child in childParts)
1701 // 1906 {
1702 child.ParentGroup.DelinkFromGroup(child, true); 1907 // Unlink all child parts from their groups
1703 1908 //
1704 // These are not in affected groups and will not be 1909 child.ParentGroup.DelinkFromGroup(child, true);
1705 // handled further. Do the honors here. 1910 child.ParentGroup.HasGroupChanged = true;
1706 child.ParentGroup.HasGroupChanged = true; 1911 child.ParentGroup.ScheduleGroupForFullUpdate();
1707 child.ParentGroup.ScheduleGroupForFullUpdate(); 1912 }
1708 } 1913 }
1709 1914
1710 foreach (SceneObjectPart root in rootParts) 1915 foreach (SceneObjectPart root in rootParts)
@@ -1714,56 +1919,68 @@ namespace OpenSim.Region.Framework.Scenes
1714 // However, editing linked parts and unlinking may be different 1919 // However, editing linked parts and unlinking may be different
1715 // 1920 //
1716 SceneObjectGroup group = root.ParentGroup; 1921 SceneObjectGroup group = root.ParentGroup;
1922 group.areUpdatesSuspended = true;
1717 1923
1718 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1924 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1719 int numChildren = newSet.Count; 1925 int numChildren = newSet.Count;
1720 1926
1927 if (numChildren == 1)
1928 break;
1929
1721 // If there are prims left in a link set, but the root is 1930 // If there are prims left in a link set, but the root is
1722 // slated for unlink, we need to do this 1931 // slated for unlink, we need to do this
1932 // Unlink the remaining set
1723 // 1933 //
1724 if (numChildren != 1) 1934 bool sendEventsToRemainder = true;
1725 { 1935 if (numChildren > 1)
1726 // Unlink the remaining set 1936 sendEventsToRemainder = false;
1727 //
1728 bool sendEventsToRemainder = true;
1729 if (numChildren > 1)
1730 sendEventsToRemainder = false;
1731 1937
1732 foreach (SceneObjectPart p in newSet) 1938 foreach (SceneObjectPart p in newSet)
1939 {
1940 if (p != group.RootPart)
1733 { 1941 {
1734 if (p != group.RootPart) 1942 group.DelinkFromGroup(p, sendEventsToRemainder);
1735 group.DelinkFromGroup(p, sendEventsToRemainder); 1943 if (numChildren > 2)
1944 {
1945 p.ParentGroup.areUpdatesSuspended = true;
1946 }
1947 else
1948 {
1949 p.ParentGroup.HasGroupChanged = true;
1950 p.ParentGroup.ScheduleGroupForFullUpdate();
1951 }
1736 } 1952 }
1953 }
1954
1955 // If there is more than one prim remaining, we
1956 // need to re-link
1957 //
1958 if (numChildren > 2)
1959 {
1960 // Remove old root
1961 //
1962 if (newSet.Contains(root))
1963 newSet.Remove(root);
1737 1964
1738 // If there is more than one prim remaining, we 1965 // Preserve link ordering
1739 // need to re-link
1740 // 1966 //
1741 if (numChildren > 2) 1967 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1742 { 1968 {
1743 // Remove old root 1969 return a.LinkNum.CompareTo(b.LinkNum);
1744 // 1970 });
1745 if (newSet.Contains(root))
1746 newSet.Remove(root);
1747
1748 // Preserve link ordering
1749 //
1750 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1751 {
1752 return a.LinkNum.CompareTo(b.LinkNum);
1753 });
1754 1971
1755 // Determine new root 1972 // Determine new root
1756 // 1973 //
1757 SceneObjectPart newRoot = newSet[0]; 1974 SceneObjectPart newRoot = newSet[0];
1758 newSet.RemoveAt(0); 1975 newSet.RemoveAt(0);
1759 1976
1760 foreach (SceneObjectPart newChild in newSet) 1977 foreach (SceneObjectPart newChild in newSet)
1761 newChild.ClearUpdateSchedule(); 1978 newChild.ClearUpdateSchedule();
1762 1979
1763 LinkObjects(newRoot, newSet); 1980 newRoot.ParentGroup.areUpdatesSuspended = true;
1764 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1981 LinkObjects(newRoot, newSet);
1765 affectedGroups.Add(newRoot.ParentGroup); 1982 if (!affectedGroups.Contains(newRoot.ParentGroup))
1766 } 1983 affectedGroups.Add(newRoot.ParentGroup);
1767 } 1984 }
1768 } 1985 }
1769 1986
@@ -1771,8 +1988,14 @@ namespace OpenSim.Region.Framework.Scenes
1771 // 1988 //
1772 foreach (SceneObjectGroup g in affectedGroups) 1989 foreach (SceneObjectGroup g in affectedGroups)
1773 { 1990 {
1991 // Child prims that have been unlinked and deleted will
1992 // return unless the root is deleted. This will remove them
1993 // from the database. They will be rewritten immediately,
1994 // minus the rows for the unlinked child prims.
1995 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1774 g.TriggerScriptChangedEvent(Changed.LINK); 1996 g.TriggerScriptChangedEvent(Changed.LINK);
1775 g.HasGroupChanged = true; // Persist 1997 g.HasGroupChanged = true; // Persist
1998 g.areUpdatesSuspended = false;
1776 g.ScheduleGroupForFullUpdate(); 1999 g.ScheduleGroupForFullUpdate();
1777 } 2000 }
1778 } 2001 }
@@ -1844,108 +2067,96 @@ namespace OpenSim.Region.Framework.Scenes
1844 /// <param name="GroupID"></param> 2067 /// <param name="GroupID"></param>
1845 /// <param name="rot"></param> 2068 /// <param name="rot"></param>
1846 /// <returns>null if duplication fails, otherwise the duplicated object</returns> 2069 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1847 public SceneObjectGroup DuplicateObject( 2070 /// <summary>
1848 uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) 2071 public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1849 { 2072 {
1850 Monitor.Enter(m_updateLock); 2073// m_log.DebugFormat(
2074// "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
2075// originalPrimID, offset, AgentID);
1851 2076
1852 try 2077 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
2078 if (original != null)
1853 { 2079 {
1854 // m_log.DebugFormat( 2080 if (m_parentScene.Permissions.CanDuplicateObject(
1855 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", 2081 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1856 // originalPrimID, offset, AgentID);
1857
1858 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1859 if (original == null)
1860 { 2082 {
1861 m_log.WarnFormat( 2083 SceneObjectGroup copy = original.Copy(true);
1862 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); 2084 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1863 2085
1864 return null; 2086 if (original.OwnerID != AgentID)
1865 } 2087 {
2088 copy.SetOwnerId(AgentID);
2089 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1866 2090
1867 if (!m_parentScene.Permissions.CanDuplicateObject( 2091 SceneObjectPart[] partList = copy.Parts;
1868 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1869 return null;
1870 2092
1871 SceneObjectGroup copy = original.Copy(true); 2093 if (m_parentScene.Permissions.PropagatePermissions())
1872 copy.AbsolutePosition = copy.AbsolutePosition + offset; 2094 {
2095 foreach (SceneObjectPart child in partList)
2096 {
2097 child.Inventory.ChangeInventoryOwner(AgentID);
2098 child.TriggerScriptChangedEvent(Changed.OWNER);
2099 child.ApplyNextOwnerPermissions();
2100 }
2101 }
2102 }
1873 2103
1874 if (original.OwnerID != AgentID) 2104 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1875 { 2105 Entities.Add(copy);
1876 copy.SetOwnerId(AgentID);
1877 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1878 2106
1879 SceneObjectPart[] partList = copy.Parts; 2107 lock (SceneObjectGroupsByFullID)
2108 SceneObjectGroupsByFullID[copy.UUID] = copy;
1880 2109
1881 if (m_parentScene.Permissions.PropagatePermissions()) 2110 SceneObjectPart[] children = copy.Parts;
2111
2112 lock (SceneObjectGroupsByFullPartID)
1882 { 2113 {
1883 foreach (SceneObjectPart child in partList) 2114 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1884 { 2115 foreach (SceneObjectPart part in children)
1885 child.Inventory.ChangeInventoryOwner(AgentID); 2116 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1886 child.TriggerScriptChangedEvent(Changed.OWNER);
1887 child.ApplyNextOwnerPermissions();
1888 }
1889 } 2117 }
1890 2118
1891 copy.RootPart.ObjectSaleType = 0; 2119 lock (SceneObjectGroupsByLocalPartID)
1892 copy.RootPart.SalePrice = 10; 2120 {
1893 } 2121 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
2122 foreach (SceneObjectPart part in children)
2123 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
2124 }
2125 // PROBABLE END OF FIXME
1894 2126
1895 // FIXME: This section needs to be refactored so that it just calls AddSceneObject() 2127 // Since we copy from a source group that is in selected
1896 Entities.Add(copy); 2128 // state, but the copy is shown deselected in the viewer,
1897 2129 // We need to clear the selection flag here, else that
1898 lock (SceneObjectGroupsByFullID) 2130 // prim never gets persisted at all. The client doesn't
1899 SceneObjectGroupsByFullID[copy.UUID] = copy; 2131 // think it's selected, so it will never send a deselect...
1900 2132 copy.IsSelected = false;
1901 SceneObjectPart[] children = copy.Parts; 2133
1902 2134 m_numPrim += copy.Parts.Length;
1903 lock (SceneObjectGroupsByFullPartID) 2135
1904 { 2136 if (rot != Quaternion.Identity)
1905 SceneObjectGroupsByFullPartID[copy.UUID] = copy; 2137 {
1906 foreach (SceneObjectPart part in children) 2138 copy.UpdateGroupRotationR(rot);
1907 SceneObjectGroupsByFullPartID[part.UUID] = copy; 2139 }
1908 }
1909
1910 lock (SceneObjectGroupsByLocalPartID)
1911 {
1912 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
1913 foreach (SceneObjectPart part in children)
1914 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
1915 }
1916 // PROBABLE END OF FIXME
1917
1918 // Since we copy from a source group that is in selected
1919 // state, but the copy is shown deselected in the viewer,
1920 // We need to clear the selection flag here, else that
1921 // prim never gets persisted at all. The client doesn't
1922 // think it's selected, so it will never send a deselect...
1923 copy.IsSelected = false;
1924
1925 m_numPrim += copy.Parts.Length;
1926
1927 if (rot != Quaternion.Identity)
1928 {
1929 copy.UpdateGroupRotationR(rot);
1930 }
1931 2140
1932 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); 2141 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1933 copy.HasGroupChanged = true; 2142 copy.HasGroupChanged = true;
1934 copy.ScheduleGroupForFullUpdate(); 2143 copy.ScheduleGroupForFullUpdate();
1935 copy.ResumeScripts(); 2144 copy.ResumeScripts();
1936 2145
1937 // required for physics to update it's position 2146 // required for physics to update it's position
1938 copy.AbsolutePosition = copy.AbsolutePosition; 2147 copy.AbsolutePosition = copy.AbsolutePosition;
1939 2148
1940 return copy; 2149 return copy;
2150 }
1941 } 2151 }
1942 finally 2152 else
1943 { 2153 {
1944 Monitor.Exit(m_updateLock); 2154 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1945 } 2155 }
2156
2157 return null;
1946 } 2158 }
1947 2159
1948 /// <summary>
1949 /// Calculates the distance between two Vector3s 2160 /// Calculates the distance between two Vector3s
1950 /// </summary> 2161 /// </summary>
1951 /// <param name="v1"></param> 2162 /// <param name="v1"></param>