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.cs477
1 files changed, 340 insertions, 137 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 13842ad..e29b2c1 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,10 @@ 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
1616 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1797 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1617 1798
1618 // We do this in reverse to get the link order of the prims correct 1799 // We do this in reverse to get the link order of the prims correct
@@ -1627,9 +1808,13 @@ namespace OpenSim.Region.Framework.Scenes
1627 // Make sure no child prim is set for sale 1808 // Make sure no child prim is set for sale
1628 // So that, on delink, no prims are unwittingly 1809 // So that, on delink, no prims are unwittingly
1629 // left for sale and sold off 1810 // left for sale and sold off
1630 child.RootPart.ObjectSaleType = 0; 1811
1631 child.RootPart.SalePrice = 10; 1812 if (child != null)
1632 childGroups.Add(child); 1813 {
1814 child.RootPart.ObjectSaleType = 0;
1815 child.RootPart.SalePrice = 10;
1816 childGroups.Add(child);
1817 }
1633 } 1818 }
1634 1819
1635 foreach (SceneObjectGroup child in childGroups) 1820 foreach (SceneObjectGroup child in childGroups)
@@ -1658,6 +1843,15 @@ namespace OpenSim.Region.Framework.Scenes
1658 } 1843 }
1659 finally 1844 finally
1660 { 1845 {
1846 lock (SceneObjectGroupsByLocalPartID)
1847 {
1848 foreach (SceneObjectPart part in parentGroup.Parts)
1849 SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
1850 }
1851
1852 parentGroup.HasGroupChanged = true;
1853 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1854 parentGroup.ScheduleGroupForFullUpdate();
1661 Monitor.Exit(m_updateLock); 1855 Monitor.Exit(m_updateLock);
1662 } 1856 }
1663 } 1857 }
@@ -1680,6 +1874,11 @@ namespace OpenSim.Region.Framework.Scenes
1680 { 1874 {
1681 if (part != null) 1875 if (part != null)
1682 { 1876 {
1877 if (part.KeyframeMotion != null)
1878 {
1879 part.KeyframeMotion.Stop();
1880 part.KeyframeMotion = null;
1881 }
1683 if (part.ParentGroup.PrimCount != 1) // Skip single 1882 if (part.ParentGroup.PrimCount != 1) // Skip single
1684 { 1883 {
1685 if (part.LinkNum < 2) // Root 1884 if (part.LinkNum < 2) // Root
@@ -1694,21 +1893,23 @@ namespace OpenSim.Region.Framework.Scenes
1694 1893
1695 SceneObjectGroup group = part.ParentGroup; 1894 SceneObjectGroup group = part.ParentGroup;
1696 if (!affectedGroups.Contains(group)) 1895 if (!affectedGroups.Contains(group))
1896 {
1697 affectedGroups.Add(group); 1897 affectedGroups.Add(group);
1898 }
1698 } 1899 }
1699 } 1900 }
1700 } 1901 }
1701 1902
1702 foreach (SceneObjectPart child in childParts) 1903 if (childParts.Count > 0)
1703 { 1904 {
1704 // Unlink all child parts from their groups 1905 foreach (SceneObjectPart child in childParts)
1705 // 1906 {
1706 child.ParentGroup.DelinkFromGroup(child, true); 1907 // Unlink all child parts from their groups
1707 1908 //
1708 // These are not in affected groups and will not be 1909 child.ParentGroup.DelinkFromGroup(child, true);
1709 // handled further. Do the honors here. 1910 child.ParentGroup.HasGroupChanged = true;
1710 child.ParentGroup.HasGroupChanged = true; 1911 child.ParentGroup.ScheduleGroupForFullUpdate();
1711 child.ParentGroup.ScheduleGroupForFullUpdate(); 1912 }
1712 } 1913 }
1713 1914
1714 foreach (SceneObjectPart root in rootParts) 1915 foreach (SceneObjectPart root in rootParts)
@@ -1722,52 +1923,61 @@ namespace OpenSim.Region.Framework.Scenes
1722 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1923 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1723 int numChildren = newSet.Count; 1924 int numChildren = newSet.Count;
1724 1925
1926 if (numChildren == 1)
1927 break;
1928
1725 // If there are prims left in a link set, but the root is 1929 // If there are prims left in a link set, but the root is
1726 // slated for unlink, we need to do this 1930 // slated for unlink, we need to do this
1931 // Unlink the remaining set
1727 // 1932 //
1728 if (numChildren != 1) 1933 bool sendEventsToRemainder = true;
1729 { 1934 if (numChildren > 1)
1730 // Unlink the remaining set 1935 sendEventsToRemainder = false;
1731 //
1732 bool sendEventsToRemainder = true;
1733 if (numChildren > 1)
1734 sendEventsToRemainder = false;
1735 1936
1736 foreach (SceneObjectPart p in newSet) 1937 foreach (SceneObjectPart p in newSet)
1938 {
1939 if (p != group.RootPart)
1737 { 1940 {
1738 if (p != group.RootPart) 1941 group.DelinkFromGroup(p, sendEventsToRemainder);
1739 group.DelinkFromGroup(p, sendEventsToRemainder); 1942 if (numChildren > 2)
1943 {
1944 }
1945 else
1946 {
1947 p.ParentGroup.HasGroupChanged = true;
1948 p.ParentGroup.ScheduleGroupForFullUpdate();
1949 }
1740 } 1950 }
1951 }
1952
1953 // If there is more than one prim remaining, we
1954 // need to re-link
1955 //
1956 if (numChildren > 2)
1957 {
1958 // Remove old root
1959 //
1960 if (newSet.Contains(root))
1961 newSet.Remove(root);
1741 1962
1742 // If there is more than one prim remaining, we 1963 // Preserve link ordering
1743 // need to re-link
1744 // 1964 //
1745 if (numChildren > 2) 1965 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1746 { 1966 {
1747 // Remove old root 1967 return a.LinkNum.CompareTo(b.LinkNum);
1748 // 1968 });
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 1969
1759 // Determine new root 1970 // Determine new root
1760 // 1971 //
1761 SceneObjectPart newRoot = newSet[0]; 1972 SceneObjectPart newRoot = newSet[0];
1762 newSet.RemoveAt(0); 1973 newSet.RemoveAt(0);
1763 1974
1764 foreach (SceneObjectPart newChild in newSet) 1975 foreach (SceneObjectPart newChild in newSet)
1765 newChild.ClearUpdateSchedule(); 1976 newChild.ClearUpdateSchedule();
1766 1977
1767 LinkObjects(newRoot, newSet); 1978 LinkObjects(newRoot, newSet);
1768 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1979 if (!affectedGroups.Contains(newRoot.ParentGroup))
1769 affectedGroups.Add(newRoot.ParentGroup); 1980 affectedGroups.Add(newRoot.ParentGroup);
1770 }
1771 } 1981 }
1772 } 1982 }
1773 1983
@@ -1775,6 +1985,11 @@ namespace OpenSim.Region.Framework.Scenes
1775 // 1985 //
1776 foreach (SceneObjectGroup g in affectedGroups) 1986 foreach (SceneObjectGroup g in affectedGroups)
1777 { 1987 {
1988 // Child prims that have been unlinked and deleted will
1989 // return unless the root is deleted. This will remove them
1990 // from the database. They will be rewritten immediately,
1991 // minus the rows for the unlinked child prims.
1992 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1778 g.TriggerScriptChangedEvent(Changed.LINK); 1993 g.TriggerScriptChangedEvent(Changed.LINK);
1779 g.HasGroupChanged = true; // Persist 1994 g.HasGroupChanged = true; // Persist
1780 g.ScheduleGroupForFullUpdate(); 1995 g.ScheduleGroupForFullUpdate();
@@ -1848,108 +2063,96 @@ namespace OpenSim.Region.Framework.Scenes
1848 /// <param name="GroupID"></param> 2063 /// <param name="GroupID"></param>
1849 /// <param name="rot"></param> 2064 /// <param name="rot"></param>
1850 /// <returns>null if duplication fails, otherwise the duplicated object</returns> 2065 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1851 public SceneObjectGroup DuplicateObject( 2066 /// <summary>
1852 uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) 2067 public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1853 { 2068 {
1854 Monitor.Enter(m_updateLock); 2069// m_log.DebugFormat(
2070// "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
2071// originalPrimID, offset, AgentID);
1855 2072
1856 try 2073 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
2074 if (original != null)
1857 { 2075 {
1858 // m_log.DebugFormat( 2076 if (m_parentScene.Permissions.CanDuplicateObject(
1859 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", 2077 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1860 // originalPrimID, offset, AgentID);
1861
1862 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1863 if (original == null)
1864 { 2078 {
1865 m_log.WarnFormat( 2079 SceneObjectGroup copy = original.Copy(true);
1866 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); 2080 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1867 2081
1868 return null; 2082 if (original.OwnerID != AgentID)
1869 } 2083 {
2084 copy.SetOwnerId(AgentID);
2085 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1870 2086
1871 if (!m_parentScene.Permissions.CanDuplicateObject( 2087 SceneObjectPart[] partList = copy.Parts;
1872 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1873 return null;
1874 2088
1875 SceneObjectGroup copy = original.Copy(true); 2089 if (m_parentScene.Permissions.PropagatePermissions())
1876 copy.AbsolutePosition = copy.AbsolutePosition + offset; 2090 {
2091 foreach (SceneObjectPart child in partList)
2092 {
2093 child.Inventory.ChangeInventoryOwner(AgentID);
2094 child.TriggerScriptChangedEvent(Changed.OWNER);
2095 child.ApplyNextOwnerPermissions();
2096 }
2097 }
2098 }
1877 2099
1878 if (original.OwnerID != AgentID) 2100 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1879 { 2101 Entities.Add(copy);
1880 copy.SetOwnerId(AgentID);
1881 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1882 2102
1883 SceneObjectPart[] partList = copy.Parts; 2103 lock (SceneObjectGroupsByFullID)
2104 SceneObjectGroupsByFullID[copy.UUID] = copy;
1884 2105
1885 if (m_parentScene.Permissions.PropagatePermissions()) 2106 SceneObjectPart[] children = copy.Parts;
2107
2108 lock (SceneObjectGroupsByFullPartID)
1886 { 2109 {
1887 foreach (SceneObjectPart child in partList) 2110 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1888 { 2111 foreach (SceneObjectPart part in children)
1889 child.Inventory.ChangeInventoryOwner(AgentID); 2112 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1890 child.TriggerScriptChangedEvent(Changed.OWNER);
1891 child.ApplyNextOwnerPermissions();
1892 }
1893 } 2113 }
1894 2114
1895 copy.RootPart.ObjectSaleType = 0; 2115 lock (SceneObjectGroupsByLocalPartID)
1896 copy.RootPart.SalePrice = 10; 2116 {
1897 } 2117 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
2118 foreach (SceneObjectPart part in children)
2119 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
2120 }
2121 // PROBABLE END OF FIXME
1898 2122
1899 // FIXME: This section needs to be refactored so that it just calls AddSceneObject() 2123 // Since we copy from a source group that is in selected
1900 Entities.Add(copy); 2124 // state, but the copy is shown deselected in the viewer,
1901 2125 // We need to clear the selection flag here, else that
1902 lock (SceneObjectGroupsByFullID) 2126 // prim never gets persisted at all. The client doesn't
1903 SceneObjectGroupsByFullID[copy.UUID] = copy; 2127 // think it's selected, so it will never send a deselect...
1904 2128 copy.IsSelected = false;
1905 SceneObjectPart[] children = copy.Parts; 2129
1906 2130 m_numPrim += copy.Parts.Length;
1907 lock (SceneObjectGroupsByFullPartID) 2131
1908 { 2132 if (rot != Quaternion.Identity)
1909 SceneObjectGroupsByFullPartID[copy.UUID] = copy; 2133 {
1910 foreach (SceneObjectPart part in children) 2134 copy.UpdateGroupRotationR(rot);
1911 SceneObjectGroupsByFullPartID[part.UUID] = copy; 2135 }
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 2136
1936 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); 2137 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1937 copy.HasGroupChanged = true; 2138 copy.HasGroupChanged = true;
1938 copy.ScheduleGroupForFullUpdate(); 2139 copy.ScheduleGroupForFullUpdate();
1939 copy.ResumeScripts(); 2140 copy.ResumeScripts();
1940 2141
1941 // required for physics to update it's position 2142 // required for physics to update it's position
1942 copy.AbsolutePosition = copy.AbsolutePosition; 2143 copy.AbsolutePosition = copy.AbsolutePosition;
1943 2144
1944 return copy; 2145 return copy;
2146 }
1945 } 2147 }
1946 finally 2148 else
1947 { 2149 {
1948 Monitor.Exit(m_updateLock); 2150 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1949 } 2151 }
2152
2153 return null;
1950 } 2154 }
1951 2155
1952 /// <summary>
1953 /// Calculates the distance between two Vector3s 2156 /// Calculates the distance between two Vector3s
1954 /// </summary> 2157 /// </summary>
1955 /// <param name="v1"></param> 2158 /// <param name="v1"></param>