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