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.cs484
1 files changed, 347 insertions, 137 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 13842ad..e0260e2 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)
@@ -1658,6 +1844,16 @@ namespace OpenSim.Region.Framework.Scenes
1658 } 1844 }
1659 finally 1845 finally
1660 { 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();
1661 Monitor.Exit(m_updateLock); 1857 Monitor.Exit(m_updateLock);
1662 } 1858 }
1663 } 1859 }
@@ -1680,6 +1876,11 @@ namespace OpenSim.Region.Framework.Scenes
1680 { 1876 {
1681 if (part != null) 1877 if (part != null)
1682 { 1878 {
1879 if (part.KeyframeMotion != null)
1880 {
1881 part.KeyframeMotion.Stop();
1882 part.KeyframeMotion = null;
1883 }
1683 if (part.ParentGroup.PrimCount != 1) // Skip single 1884 if (part.ParentGroup.PrimCount != 1) // Skip single
1684 { 1885 {
1685 if (part.LinkNum < 2) // Root 1886 if (part.LinkNum < 2) // Root
@@ -1694,21 +1895,24 @@ namespace OpenSim.Region.Framework.Scenes
1694 1895
1695 SceneObjectGroup group = part.ParentGroup; 1896 SceneObjectGroup group = part.ParentGroup;
1696 if (!affectedGroups.Contains(group)) 1897 if (!affectedGroups.Contains(group))
1898 {
1899 group.areUpdatesSuspended = true;
1697 affectedGroups.Add(group); 1900 affectedGroups.Add(group);
1901 }
1698 } 1902 }
1699 } 1903 }
1700 } 1904 }
1701 1905
1702 foreach (SceneObjectPart child in childParts) 1906 if (childParts.Count > 0)
1703 { 1907 {
1704 // Unlink all child parts from their groups 1908 foreach (SceneObjectPart child in childParts)
1705 // 1909 {
1706 child.ParentGroup.DelinkFromGroup(child, true); 1910 // Unlink all child parts from their groups
1707 1911 //
1708 // These are not in affected groups and will not be 1912 child.ParentGroup.DelinkFromGroup(child, true);
1709 // handled further. Do the honors here. 1913 child.ParentGroup.HasGroupChanged = true;
1710 child.ParentGroup.HasGroupChanged = true; 1914 child.ParentGroup.ScheduleGroupForFullUpdate();
1711 child.ParentGroup.ScheduleGroupForFullUpdate(); 1915 }
1712 } 1916 }
1713 1917
1714 foreach (SceneObjectPart root in rootParts) 1918 foreach (SceneObjectPart root in rootParts)
@@ -1718,56 +1922,68 @@ namespace OpenSim.Region.Framework.Scenes
1718 // However, editing linked parts and unlinking may be different 1922 // However, editing linked parts and unlinking may be different
1719 // 1923 //
1720 SceneObjectGroup group = root.ParentGroup; 1924 SceneObjectGroup group = root.ParentGroup;
1925 group.areUpdatesSuspended = true;
1721 1926
1722 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1927 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1723 int numChildren = newSet.Count; 1928 int numChildren = newSet.Count;
1724 1929
1930 if (numChildren == 1)
1931 break;
1932
1725 // 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
1726 // slated for unlink, we need to do this 1934 // slated for unlink, we need to do this
1935 // Unlink the remaining set
1727 // 1936 //
1728 if (numChildren != 1) 1937 bool sendEventsToRemainder = true;
1729 { 1938 if (numChildren > 1)
1730 // Unlink the remaining set 1939 sendEventsToRemainder = false;
1731 //
1732 bool sendEventsToRemainder = true;
1733 if (numChildren > 1)
1734 sendEventsToRemainder = false;
1735 1940
1736 foreach (SceneObjectPart p in newSet) 1941 foreach (SceneObjectPart p in newSet)
1942 {
1943 if (p != group.RootPart)
1737 { 1944 {
1738 if (p != group.RootPart) 1945 group.DelinkFromGroup(p, sendEventsToRemainder);
1739 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 }
1740 } 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);
1741 1967
1742 // If there is more than one prim remaining, we 1968 // Preserve link ordering
1743 // need to re-link
1744 // 1969 //
1745 if (numChildren > 2) 1970 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1746 { 1971 {
1747 // Remove old root 1972 return a.LinkNum.CompareTo(b.LinkNum);
1748 // 1973 });
1749 if (newSet.Contains(root))
1750 newSet.Remove(root);
1751
1752 // Preserve link ordering
1753 //
1754 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1755 {
1756 return a.LinkNum.CompareTo(b.LinkNum);
1757 });
1758 1974
1759 // Determine new root 1975 // Determine new root
1760 // 1976 //
1761 SceneObjectPart newRoot = newSet[0]; 1977 SceneObjectPart newRoot = newSet[0];
1762 newSet.RemoveAt(0); 1978 newSet.RemoveAt(0);
1763 1979
1764 foreach (SceneObjectPart newChild in newSet) 1980 foreach (SceneObjectPart newChild in newSet)
1765 newChild.ClearUpdateSchedule(); 1981 newChild.ClearUpdateSchedule();
1766 1982
1767 LinkObjects(newRoot, newSet); 1983 newRoot.ParentGroup.areUpdatesSuspended = true;
1768 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1984 LinkObjects(newRoot, newSet);
1769 affectedGroups.Add(newRoot.ParentGroup); 1985 if (!affectedGroups.Contains(newRoot.ParentGroup))
1770 } 1986 affectedGroups.Add(newRoot.ParentGroup);
1771 } 1987 }
1772 } 1988 }
1773 1989
@@ -1775,8 +1991,14 @@ namespace OpenSim.Region.Framework.Scenes
1775 // 1991 //
1776 foreach (SceneObjectGroup g in affectedGroups) 1992 foreach (SceneObjectGroup g in affectedGroups)
1777 { 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);
1778 g.TriggerScriptChangedEvent(Changed.LINK); 1999 g.TriggerScriptChangedEvent(Changed.LINK);
1779 g.HasGroupChanged = true; // Persist 2000 g.HasGroupChanged = true; // Persist
2001 g.areUpdatesSuspended = false;
1780 g.ScheduleGroupForFullUpdate(); 2002 g.ScheduleGroupForFullUpdate();
1781 } 2003 }
1782 } 2004 }
@@ -1848,108 +2070,96 @@ namespace OpenSim.Region.Framework.Scenes
1848 /// <param name="GroupID"></param> 2070 /// <param name="GroupID"></param>
1849 /// <param name="rot"></param> 2071 /// <param name="rot"></param>
1850 /// <returns>null if duplication fails, otherwise the duplicated object</returns> 2072 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1851 public SceneObjectGroup DuplicateObject( 2073 /// <summary>
1852 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)
1853 { 2075 {
1854 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);
1855 2079
1856 try 2080 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
2081 if (original != null)
1857 { 2082 {
1858 // m_log.DebugFormat( 2083 if (m_parentScene.Permissions.CanDuplicateObject(
1859 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", 2084 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1860 // originalPrimID, offset, AgentID);
1861
1862 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1863 if (original == null)
1864 { 2085 {
1865 m_log.WarnFormat( 2086 SceneObjectGroup copy = original.Copy(true);
1866 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); 2087 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1867 2088
1868 return null; 2089 if (original.OwnerID != AgentID)
1869 } 2090 {
2091 copy.SetOwnerId(AgentID);
2092 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1870 2093
1871 if (!m_parentScene.Permissions.CanDuplicateObject( 2094 SceneObjectPart[] partList = copy.Parts;
1872 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1873 return null;
1874 2095
1875 SceneObjectGroup copy = original.Copy(true); 2096 if (m_parentScene.Permissions.PropagatePermissions())
1876 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 }
1877 2106
1878 if (original.OwnerID != AgentID) 2107 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1879 { 2108 Entities.Add(copy);
1880 copy.SetOwnerId(AgentID);
1881 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1882 2109
1883 SceneObjectPart[] partList = copy.Parts; 2110 lock (SceneObjectGroupsByFullID)
2111 SceneObjectGroupsByFullID[copy.UUID] = copy;
1884 2112
1885 if (m_parentScene.Permissions.PropagatePermissions()) 2113 SceneObjectPart[] children = copy.Parts;
2114
2115 lock (SceneObjectGroupsByFullPartID)
1886 { 2116 {
1887 foreach (SceneObjectPart child in partList) 2117 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1888 { 2118 foreach (SceneObjectPart part in children)
1889 child.Inventory.ChangeInventoryOwner(AgentID); 2119 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1890 child.TriggerScriptChangedEvent(Changed.OWNER);
1891 child.ApplyNextOwnerPermissions();
1892 }
1893 } 2120 }
1894 2121
1895 copy.RootPart.ObjectSaleType = 0; 2122 lock (SceneObjectGroupsByLocalPartID)
1896 copy.RootPart.SalePrice = 10; 2123 {
1897 } 2124 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
2125 foreach (SceneObjectPart part in children)
2126 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
2127 }
2128 // PROBABLE END OF FIXME
1898 2129
1899 // 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
1900 Entities.Add(copy); 2131 // state, but the copy is shown deselected in the viewer,
1901 2132 // We need to clear the selection flag here, else that
1902 lock (SceneObjectGroupsByFullID) 2133 // prim never gets persisted at all. The client doesn't
1903 SceneObjectGroupsByFullID[copy.UUID] = copy; 2134 // think it's selected, so it will never send a deselect...
1904 2135 copy.IsSelected = false;
1905 SceneObjectPart[] children = copy.Parts; 2136
1906 2137 m_numPrim += copy.Parts.Length;
1907 lock (SceneObjectGroupsByFullPartID) 2138
1908 { 2139 if (rot != Quaternion.Identity)
1909 SceneObjectGroupsByFullPartID[copy.UUID] = copy; 2140 {
1910 foreach (SceneObjectPart part in children) 2141 copy.UpdateGroupRotationR(rot);
1911 SceneObjectGroupsByFullPartID[part.UUID] = copy; 2142 }
1912 }
1913
1914 lock (SceneObjectGroupsByLocalPartID)
1915 {
1916 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
1917 foreach (SceneObjectPart part in children)
1918 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
1919 }
1920 // PROBABLE END OF FIXME
1921
1922 // Since we copy from a source group that is in selected
1923 // state, but the copy is shown deselected in the viewer,
1924 // We need to clear the selection flag here, else that
1925 // prim never gets persisted at all. The client doesn't
1926 // think it's selected, so it will never send a deselect...
1927 copy.IsSelected = false;
1928
1929 m_numPrim += copy.Parts.Length;
1930
1931 if (rot != Quaternion.Identity)
1932 {
1933 copy.UpdateGroupRotationR(rot);
1934 }
1935 2143
1936 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); 2144 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1937 copy.HasGroupChanged = true; 2145 copy.HasGroupChanged = true;
1938 copy.ScheduleGroupForFullUpdate(); 2146 copy.ScheduleGroupForFullUpdate();
1939 copy.ResumeScripts(); 2147 copy.ResumeScripts();
1940 2148
1941 // required for physics to update it's position 2149 // required for physics to update it's position
1942 copy.AbsolutePosition = copy.AbsolutePosition; 2150 copy.AbsolutePosition = copy.AbsolutePosition;
1943 2151
1944 return copy; 2152 return copy;
2153 }
1945 } 2154 }
1946 finally 2155 else
1947 { 2156 {
1948 Monitor.Exit(m_updateLock); 2157 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1949 } 2158 }
2159
2160 return null;
1950 } 2161 }
1951 2162
1952 /// <summary>
1953 /// Calculates the distance between two Vector3s 2163 /// Calculates the distance between two Vector3s
1954 /// </summary> 2164 /// </summary>
1955 /// <param name="v1"></param> 2165 /// <param name="v1"></param>