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 a59758f..4c12496 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)
@@ -1176,6 +1256,52 @@ namespace OpenSim.Region.Framework.Scenes
1176 1256
1177 #region Client Event handlers 1257 #region Client Event handlers
1178 1258
1259 protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient)
1260 {
1261 SceneObjectPart part = GetSceneObjectPart(localID);
1262 ObjectChangeData data = (ObjectChangeData)odata;
1263
1264 if (part != null)
1265 {
1266 SceneObjectGroup grp = part.ParentGroup;
1267 if (grp != null)
1268 {
1269 if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId))
1270 {
1271 // These two are exceptions SL makes in the interpretation
1272 // of the change flags. Must check them here because otherwise
1273 // the group flag (see below) would be lost
1274 if (data.change == ObjectChangeType.groupS)
1275 data.change = ObjectChangeType.primS;
1276 if (data.change == ObjectChangeType.groupPS)
1277 data.change = ObjectChangeType.primPS;
1278 part.StoreUndoState(data.change); // lets test only saving what we changed
1279 grp.doChangeObject(part, (ObjectChangeData)data);
1280 }
1281 else
1282 {
1283 // Is this any kind of group operation?
1284 if ((data.change & ObjectChangeType.Group) != 0)
1285 {
1286 // Is a move and/or rotation requested?
1287 if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0)
1288 {
1289 // Are we allowed to move it?
1290 if (m_parentScene.Permissions.CanMoveObject(grp.UUID, remoteClient.AgentId))
1291 {
1292 // Strip all but move and rotation from request
1293 data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation);
1294
1295 part.StoreUndoState(data.change);
1296 grp.doChangeObject(part, (ObjectChangeData)data);
1297 }
1298 }
1299 }
1300 }
1301 }
1302 }
1303 }
1304
1179 /// <summary> 1305 /// <summary>
1180 /// Update the scale of an individual prim. 1306 /// Update the scale of an individual prim.
1181 /// </summary> 1307 /// </summary>
@@ -1190,7 +1316,17 @@ namespace OpenSim.Region.Framework.Scenes
1190 { 1316 {
1191 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) 1317 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId))
1192 { 1318 {
1319 bool physbuild = false;
1320 if (part.ParentGroup.RootPart.PhysActor != null)
1321 {
1322 part.ParentGroup.RootPart.PhysActor.Building = true;
1323 physbuild = true;
1324 }
1325
1193 part.Resize(scale); 1326 part.Resize(scale);
1327
1328 if (physbuild)
1329 part.ParentGroup.RootPart.PhysActor.Building = false;
1194 } 1330 }
1195 } 1331 }
1196 } 1332 }
@@ -1202,7 +1338,17 @@ namespace OpenSim.Region.Framework.Scenes
1202 { 1338 {
1203 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1339 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1204 { 1340 {
1341 bool physbuild = false;
1342 if (group.RootPart.PhysActor != null)
1343 {
1344 group.RootPart.PhysActor.Building = true;
1345 physbuild = true;
1346 }
1347
1205 group.GroupResize(scale); 1348 group.GroupResize(scale);
1349
1350 if (physbuild)
1351 group.RootPart.PhysActor.Building = false;
1206 } 1352 }
1207 } 1353 }
1208 } 1354 }
@@ -1330,8 +1476,13 @@ namespace OpenSim.Region.Framework.Scenes
1330 { 1476 {
1331 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) 1477 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1332 { 1478 {
1333 if (m_parentScene.AttachmentsModule != null) 1479 // Set the new attachment point data in the object
1334 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); 1480 byte attachmentPoint = group.GetAttachmentPoint();
1481 group.UpdateGroupPosition(pos);
1482 group.IsAttachment = false;
1483 group.AbsolutePosition = group.RootPart.AttachedPos;
1484 group.AttachmentPoint = attachmentPoint;
1485 group.HasGroupChanged = true;
1335 } 1486 }
1336 else 1487 else
1337 { 1488 {
@@ -1379,7 +1530,7 @@ namespace OpenSim.Region.Framework.Scenes
1379 /// <param name="SetPhantom"></param> 1530 /// <param name="SetPhantom"></param>
1380 /// <param name="remoteClient"></param> 1531 /// <param name="remoteClient"></param>
1381 protected internal void UpdatePrimFlags( 1532 protected internal void UpdatePrimFlags(
1382 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) 1533 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1383 { 1534 {
1384 SceneObjectGroup group = GetGroupByPrim(localID); 1535 SceneObjectGroup group = GetGroupByPrim(localID);
1385 if (group != null) 1536 if (group != null)
@@ -1387,7 +1538,28 @@ namespace OpenSim.Region.Framework.Scenes
1387 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1538 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1388 { 1539 {
1389 // VolumeDetect can't be set via UI and will always be off when a change is made there 1540 // VolumeDetect can't be set via UI and will always be off when a change is made there
1390 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); 1541 // now only change volume dtc if phantom off
1542
1543 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1544 {
1545 bool vdtc;
1546 if (SetPhantom) // if phantom keep volumedtc
1547 vdtc = group.RootPart.VolumeDetectActive;
1548 else // else turn it off
1549 vdtc = false;
1550
1551 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1552 }
1553 else
1554 {
1555 SceneObjectPart part = GetSceneObjectPart(localID);
1556 if (part != null)
1557 {
1558 part.UpdateExtraPhysics(PhysData);
1559 if (part.UpdatePhysRequired)
1560 remoteClient.SendPartPhysicsProprieties(part);
1561 }
1562 }
1391 } 1563 }
1392 } 1564 }
1393 } 1565 }
@@ -1531,6 +1703,7 @@ namespace OpenSim.Region.Framework.Scenes
1531 { 1703 {
1532 part.Material = Convert.ToByte(material); 1704 part.Material = Convert.ToByte(material);
1533 group.HasGroupChanged = true; 1705 group.HasGroupChanged = true;
1706 remoteClient.SendPartPhysicsProprieties(part);
1534 } 1707 }
1535 } 1708 }
1536 } 1709 }
@@ -1595,6 +1768,12 @@ namespace OpenSim.Region.Framework.Scenes
1595 /// <param name="childPrims"></param> 1768 /// <param name="childPrims"></param>
1596 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1769 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1597 { 1770 {
1771 if (root.KeyframeMotion != null)
1772 {
1773 root.KeyframeMotion.Stop();
1774 root.KeyframeMotion = null;
1775 }
1776
1598 SceneObjectGroup parentGroup = root.ParentGroup; 1777 SceneObjectGroup parentGroup = root.ParentGroup;
1599 if (parentGroup == null) return; 1778 if (parentGroup == null) return;
1600 1779
@@ -1603,8 +1782,11 @@ namespace OpenSim.Region.Framework.Scenes
1603 return; 1782 return;
1604 1783
1605 Monitor.Enter(m_updateLock); 1784 Monitor.Enter(m_updateLock);
1785
1606 try 1786 try
1607 { 1787 {
1788 parentGroup.areUpdatesSuspended = true;
1789
1608 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1790 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1609 1791
1610 // We do this in reverse to get the link order of the prims correct 1792 // We do this in reverse to get the link order of the prims correct
@@ -1619,9 +1801,13 @@ namespace OpenSim.Region.Framework.Scenes
1619 // Make sure no child prim is set for sale 1801 // Make sure no child prim is set for sale
1620 // So that, on delink, no prims are unwittingly 1802 // So that, on delink, no prims are unwittingly
1621 // left for sale and sold off 1803 // left for sale and sold off
1622 child.RootPart.ObjectSaleType = 0; 1804
1623 child.RootPart.SalePrice = 10; 1805 if (child != null)
1624 childGroups.Add(child); 1806 {
1807 child.RootPart.ObjectSaleType = 0;
1808 child.RootPart.SalePrice = 10;
1809 childGroups.Add(child);
1810 }
1625 } 1811 }
1626 1812
1627 foreach (SceneObjectGroup child in childGroups) 1813 foreach (SceneObjectGroup child in childGroups)
@@ -1648,6 +1834,16 @@ namespace OpenSim.Region.Framework.Scenes
1648 } 1834 }
1649 finally 1835 finally
1650 { 1836 {
1837 lock (SceneObjectGroupsByLocalPartID)
1838 {
1839 foreach (SceneObjectPart part in parentGroup.Parts)
1840 SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
1841 }
1842
1843 parentGroup.areUpdatesSuspended = false;
1844 parentGroup.HasGroupChanged = true;
1845 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1846 parentGroup.ScheduleGroupForFullUpdate();
1651 Monitor.Exit(m_updateLock); 1847 Monitor.Exit(m_updateLock);
1652 } 1848 }
1653 } 1849 }
@@ -1670,6 +1866,11 @@ namespace OpenSim.Region.Framework.Scenes
1670 { 1866 {
1671 if (part != null) 1867 if (part != null)
1672 { 1868 {
1869 if (part.KeyframeMotion != null)
1870 {
1871 part.KeyframeMotion.Stop();
1872 part.KeyframeMotion = null;
1873 }
1673 if (part.ParentGroup.PrimCount != 1) // Skip single 1874 if (part.ParentGroup.PrimCount != 1) // Skip single
1674 { 1875 {
1675 if (part.LinkNum < 2) // Root 1876 if (part.LinkNum < 2) // Root
@@ -1684,21 +1885,24 @@ namespace OpenSim.Region.Framework.Scenes
1684 1885
1685 SceneObjectGroup group = part.ParentGroup; 1886 SceneObjectGroup group = part.ParentGroup;
1686 if (!affectedGroups.Contains(group)) 1887 if (!affectedGroups.Contains(group))
1888 {
1889 group.areUpdatesSuspended = true;
1687 affectedGroups.Add(group); 1890 affectedGroups.Add(group);
1891 }
1688 } 1892 }
1689 } 1893 }
1690 } 1894 }
1691 1895
1692 foreach (SceneObjectPart child in childParts) 1896 if (childParts.Count > 0)
1693 { 1897 {
1694 // Unlink all child parts from their groups 1898 foreach (SceneObjectPart child in childParts)
1695 // 1899 {
1696 child.ParentGroup.DelinkFromGroup(child, true); 1900 // Unlink all child parts from their groups
1697 1901 //
1698 // These are not in affected groups and will not be 1902 child.ParentGroup.DelinkFromGroup(child, true);
1699 // handled further. Do the honors here. 1903 child.ParentGroup.HasGroupChanged = true;
1700 child.ParentGroup.HasGroupChanged = true; 1904 child.ParentGroup.ScheduleGroupForFullUpdate();
1701 child.ParentGroup.ScheduleGroupForFullUpdate(); 1905 }
1702 } 1906 }
1703 1907
1704 foreach (SceneObjectPart root in rootParts) 1908 foreach (SceneObjectPart root in rootParts)
@@ -1708,56 +1912,68 @@ namespace OpenSim.Region.Framework.Scenes
1708 // However, editing linked parts and unlinking may be different 1912 // However, editing linked parts and unlinking may be different
1709 // 1913 //
1710 SceneObjectGroup group = root.ParentGroup; 1914 SceneObjectGroup group = root.ParentGroup;
1915 group.areUpdatesSuspended = true;
1711 1916
1712 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1917 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1713 int numChildren = newSet.Count; 1918 int numChildren = newSet.Count;
1714 1919
1920 if (numChildren == 1)
1921 break;
1922
1715 // If there are prims left in a link set, but the root is 1923 // If there are prims left in a link set, but the root is
1716 // slated for unlink, we need to do this 1924 // slated for unlink, we need to do this
1925 // Unlink the remaining set
1717 // 1926 //
1718 if (numChildren != 1) 1927 bool sendEventsToRemainder = true;
1719 { 1928 if (numChildren > 1)
1720 // Unlink the remaining set 1929 sendEventsToRemainder = false;
1721 //
1722 bool sendEventsToRemainder = true;
1723 if (numChildren > 1)
1724 sendEventsToRemainder = false;
1725 1930
1726 foreach (SceneObjectPart p in newSet) 1931 foreach (SceneObjectPart p in newSet)
1932 {
1933 if (p != group.RootPart)
1727 { 1934 {
1728 if (p != group.RootPart) 1935 group.DelinkFromGroup(p, sendEventsToRemainder);
1729 group.DelinkFromGroup(p, sendEventsToRemainder); 1936 if (numChildren > 2)
1937 {
1938 p.ParentGroup.areUpdatesSuspended = true;
1939 }
1940 else
1941 {
1942 p.ParentGroup.HasGroupChanged = true;
1943 p.ParentGroup.ScheduleGroupForFullUpdate();
1944 }
1730 } 1945 }
1946 }
1947
1948 // If there is more than one prim remaining, we
1949 // need to re-link
1950 //
1951 if (numChildren > 2)
1952 {
1953 // Remove old root
1954 //
1955 if (newSet.Contains(root))
1956 newSet.Remove(root);
1731 1957
1732 // If there is more than one prim remaining, we 1958 // Preserve link ordering
1733 // need to re-link
1734 // 1959 //
1735 if (numChildren > 2) 1960 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1736 { 1961 {
1737 // Remove old root 1962 return a.LinkNum.CompareTo(b.LinkNum);
1738 // 1963 });
1739 if (newSet.Contains(root))
1740 newSet.Remove(root);
1741
1742 // Preserve link ordering
1743 //
1744 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1745 {
1746 return a.LinkNum.CompareTo(b.LinkNum);
1747 });
1748 1964
1749 // Determine new root 1965 // Determine new root
1750 // 1966 //
1751 SceneObjectPart newRoot = newSet[0]; 1967 SceneObjectPart newRoot = newSet[0];
1752 newSet.RemoveAt(0); 1968 newSet.RemoveAt(0);
1753 1969
1754 foreach (SceneObjectPart newChild in newSet) 1970 foreach (SceneObjectPart newChild in newSet)
1755 newChild.ClearUpdateSchedule(); 1971 newChild.ClearUpdateSchedule();
1756 1972
1757 LinkObjects(newRoot, newSet); 1973 newRoot.ParentGroup.areUpdatesSuspended = true;
1758 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1974 LinkObjects(newRoot, newSet);
1759 affectedGroups.Add(newRoot.ParentGroup); 1975 if (!affectedGroups.Contains(newRoot.ParentGroup))
1760 } 1976 affectedGroups.Add(newRoot.ParentGroup);
1761 } 1977 }
1762 } 1978 }
1763 1979
@@ -1765,8 +1981,14 @@ namespace OpenSim.Region.Framework.Scenes
1765 // 1981 //
1766 foreach (SceneObjectGroup g in affectedGroups) 1982 foreach (SceneObjectGroup g in affectedGroups)
1767 { 1983 {
1984 // Child prims that have been unlinked and deleted will
1985 // return unless the root is deleted. This will remove them
1986 // from the database. They will be rewritten immediately,
1987 // minus the rows for the unlinked child prims.
1988 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1768 g.TriggerScriptChangedEvent(Changed.LINK); 1989 g.TriggerScriptChangedEvent(Changed.LINK);
1769 g.HasGroupChanged = true; // Persist 1990 g.HasGroupChanged = true; // Persist
1991 g.areUpdatesSuspended = false;
1770 g.ScheduleGroupForFullUpdate(); 1992 g.ScheduleGroupForFullUpdate();
1771 } 1993 }
1772 } 1994 }
@@ -1838,108 +2060,96 @@ namespace OpenSim.Region.Framework.Scenes
1838 /// <param name="GroupID"></param> 2060 /// <param name="GroupID"></param>
1839 /// <param name="rot"></param> 2061 /// <param name="rot"></param>
1840 /// <returns>null if duplication fails, otherwise the duplicated object</returns> 2062 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1841 public SceneObjectGroup DuplicateObject( 2063 /// <summary>
1842 uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) 2064 public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1843 { 2065 {
1844 Monitor.Enter(m_updateLock); 2066// m_log.DebugFormat(
2067// "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
2068// originalPrimID, offset, AgentID);
1845 2069
1846 try 2070 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
2071 if (original != null)
1847 { 2072 {
1848 // m_log.DebugFormat( 2073 if (m_parentScene.Permissions.CanDuplicateObject(
1849 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", 2074 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1850 // originalPrimID, offset, AgentID);
1851
1852 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1853 if (original == null)
1854 { 2075 {
1855 m_log.WarnFormat( 2076 SceneObjectGroup copy = original.Copy(true);
1856 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); 2077 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1857 2078
1858 return null; 2079 if (original.OwnerID != AgentID)
1859 } 2080 {
2081 copy.SetOwnerId(AgentID);
2082 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1860 2083
1861 if (!m_parentScene.Permissions.CanDuplicateObject( 2084 SceneObjectPart[] partList = copy.Parts;
1862 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1863 return null;
1864 2085
1865 SceneObjectGroup copy = original.Copy(true); 2086 if (m_parentScene.Permissions.PropagatePermissions())
1866 copy.AbsolutePosition = copy.AbsolutePosition + offset; 2087 {
2088 foreach (SceneObjectPart child in partList)
2089 {
2090 child.Inventory.ChangeInventoryOwner(AgentID);
2091 child.TriggerScriptChangedEvent(Changed.OWNER);
2092 child.ApplyNextOwnerPermissions();
2093 }
2094 }
2095 }
1867 2096
1868 if (original.OwnerID != AgentID) 2097 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1869 { 2098 Entities.Add(copy);
1870 copy.SetOwnerId(AgentID);
1871 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1872 2099
1873 SceneObjectPart[] partList = copy.Parts; 2100 lock (SceneObjectGroupsByFullID)
2101 SceneObjectGroupsByFullID[copy.UUID] = copy;
1874 2102
1875 if (m_parentScene.Permissions.PropagatePermissions()) 2103 SceneObjectPart[] children = copy.Parts;
2104
2105 lock (SceneObjectGroupsByFullPartID)
1876 { 2106 {
1877 foreach (SceneObjectPart child in partList) 2107 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1878 { 2108 foreach (SceneObjectPart part in children)
1879 child.Inventory.ChangeInventoryOwner(AgentID); 2109 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1880 child.TriggerScriptChangedEvent(Changed.OWNER);
1881 child.ApplyNextOwnerPermissions();
1882 }
1883 } 2110 }
1884 2111
1885 copy.RootPart.ObjectSaleType = 0; 2112 lock (SceneObjectGroupsByLocalPartID)
1886 copy.RootPart.SalePrice = 10; 2113 {
1887 } 2114 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
2115 foreach (SceneObjectPart part in children)
2116 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
2117 }
2118 // PROBABLE END OF FIXME
1888 2119
1889 // FIXME: This section needs to be refactored so that it just calls AddSceneObject() 2120 // Since we copy from a source group that is in selected
1890 Entities.Add(copy); 2121 // state, but the copy is shown deselected in the viewer,
1891 2122 // We need to clear the selection flag here, else that
1892 lock (SceneObjectGroupsByFullID) 2123 // prim never gets persisted at all. The client doesn't
1893 SceneObjectGroupsByFullID[copy.UUID] = copy; 2124 // think it's selected, so it will never send a deselect...
1894 2125 copy.IsSelected = false;
1895 SceneObjectPart[] children = copy.Parts; 2126
1896 2127 m_numPrim += copy.Parts.Length;
1897 lock (SceneObjectGroupsByFullPartID) 2128
1898 { 2129 if (rot != Quaternion.Identity)
1899 SceneObjectGroupsByFullPartID[copy.UUID] = copy; 2130 {
1900 foreach (SceneObjectPart part in children) 2131 copy.UpdateGroupRotationR(rot);
1901 SceneObjectGroupsByFullPartID[part.UUID] = copy; 2132 }
1902 }
1903
1904 lock (SceneObjectGroupsByLocalPartID)
1905 {
1906 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
1907 foreach (SceneObjectPart part in children)
1908 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
1909 }
1910 // PROBABLE END OF FIXME
1911
1912 // Since we copy from a source group that is in selected
1913 // state, but the copy is shown deselected in the viewer,
1914 // We need to clear the selection flag here, else that
1915 // prim never gets persisted at all. The client doesn't
1916 // think it's selected, so it will never send a deselect...
1917 copy.IsSelected = false;
1918
1919 m_numPrim += copy.Parts.Length;
1920
1921 if (rot != Quaternion.Identity)
1922 {
1923 copy.UpdateGroupRotationR(rot);
1924 }
1925 2133
1926 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); 2134 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1927 copy.HasGroupChanged = true; 2135 copy.HasGroupChanged = true;
1928 copy.ScheduleGroupForFullUpdate(); 2136 copy.ScheduleGroupForFullUpdate();
1929 copy.ResumeScripts(); 2137 copy.ResumeScripts();
1930 2138
1931 // required for physics to update it's position 2139 // required for physics to update it's position
1932 copy.AbsolutePosition = copy.AbsolutePosition; 2140 copy.AbsolutePosition = copy.AbsolutePosition;
1933 2141
1934 return copy; 2142 return copy;
2143 }
1935 } 2144 }
1936 finally 2145 else
1937 { 2146 {
1938 Monitor.Exit(m_updateLock); 2147 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1939 } 2148 }
2149
2150 return null;
1940 } 2151 }
1941 2152
1942 /// <summary>
1943 /// Calculates the distance between two Vector3s 2153 /// Calculates the distance between two Vector3s
1944 /// </summary> 2154 /// </summary>
1945 /// <param name="v1"></param> 2155 /// <param name="v1"></param>