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