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