diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 479 |
1 files changed, 345 insertions, 134 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 4815922..00f76e0 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(); |
@@ -319,7 +361,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
319 | sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false); | 361 | sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false); |
320 | sceneObject.Velocity = vel; | 362 | sceneObject.Velocity = vel; |
321 | } | 363 | } |
322 | 364 | ||
323 | return true; | 365 | return true; |
324 | } | 366 | } |
325 | 367 | ||
@@ -344,6 +386,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
344 | /// </returns> | 386 | /// </returns> |
345 | protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) | 387 | protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) |
346 | { | 388 | { |
389 | if (sceneObject == null) | ||
390 | { | ||
391 | m_log.ErrorFormat("[SCENEGRAPH]: Tried to add null scene object"); | ||
392 | return false; | ||
393 | } | ||
347 | if (sceneObject.UUID == UUID.Zero) | 394 | if (sceneObject.UUID == UUID.Zero) |
348 | { | 395 | { |
349 | m_log.ErrorFormat( | 396 | m_log.ErrorFormat( |
@@ -478,6 +525,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
478 | m_updateList[obj.UUID] = obj; | 525 | m_updateList[obj.UUID] = obj; |
479 | } | 526 | } |
480 | 527 | ||
528 | public void FireAttachToBackup(SceneObjectGroup obj) | ||
529 | { | ||
530 | if (OnAttachToBackup != null) | ||
531 | { | ||
532 | OnAttachToBackup(obj); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | public void FireDetachFromBackup(SceneObjectGroup obj) | ||
537 | { | ||
538 | if (OnDetachFromBackup != null) | ||
539 | { | ||
540 | OnDetachFromBackup(obj); | ||
541 | } | ||
542 | } | ||
543 | |||
544 | public void FireChangeBackup(SceneObjectGroup obj) | ||
545 | { | ||
546 | if (OnChangeBackup != null) | ||
547 | { | ||
548 | OnChangeBackup(obj); | ||
549 | } | ||
550 | } | ||
551 | |||
481 | /// <summary> | 552 | /// <summary> |
482 | /// Process all pending updates | 553 | /// Process all pending updates |
483 | /// </summary> | 554 | /// </summary> |
@@ -595,7 +666,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
595 | 666 | ||
596 | Entities[presence.UUID] = presence; | 667 | Entities[presence.UUID] = presence; |
597 | 668 | ||
598 | lock (m_presenceLock) | 669 | m_scenePresencesLock.EnterWriteLock(); |
670 | try | ||
599 | { | 671 | { |
600 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); | 672 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); |
601 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); | 673 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); |
@@ -619,6 +691,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
619 | m_scenePresenceMap = newmap; | 691 | m_scenePresenceMap = newmap; |
620 | m_scenePresenceArray = newlist; | 692 | m_scenePresenceArray = newlist; |
621 | } | 693 | } |
694 | finally | ||
695 | { | ||
696 | m_scenePresencesLock.ExitWriteLock(); | ||
697 | } | ||
622 | } | 698 | } |
623 | 699 | ||
624 | /// <summary> | 700 | /// <summary> |
@@ -633,7 +709,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
633 | agentID); | 709 | agentID); |
634 | } | 710 | } |
635 | 711 | ||
636 | lock (m_presenceLock) | 712 | m_scenePresencesLock.EnterWriteLock(); |
713 | try | ||
637 | { | 714 | { |
638 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); | 715 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); |
639 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); | 716 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); |
@@ -655,6 +732,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); | 732 | m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); |
656 | } | 733 | } |
657 | } | 734 | } |
735 | finally | ||
736 | { | ||
737 | m_scenePresencesLock.ExitWriteLock(); | ||
738 | } | ||
658 | } | 739 | } |
659 | 740 | ||
660 | protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) | 741 | protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) |
@@ -1187,6 +1268,52 @@ namespace OpenSim.Region.Framework.Scenes | |||
1187 | 1268 | ||
1188 | #region Client Event handlers | 1269 | #region Client Event handlers |
1189 | 1270 | ||
1271 | protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient) | ||
1272 | { | ||
1273 | SceneObjectPart part = GetSceneObjectPart(localID); | ||
1274 | ObjectChangeData data = (ObjectChangeData)odata; | ||
1275 | |||
1276 | if (part != null) | ||
1277 | { | ||
1278 | SceneObjectGroup grp = part.ParentGroup; | ||
1279 | if (grp != null) | ||
1280 | { | ||
1281 | if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId)) | ||
1282 | { | ||
1283 | // These two are exceptions SL makes in the interpretation | ||
1284 | // of the change flags. Must check them here because otherwise | ||
1285 | // the group flag (see below) would be lost | ||
1286 | if (data.change == ObjectChangeType.groupS) | ||
1287 | data.change = ObjectChangeType.primS; | ||
1288 | if (data.change == ObjectChangeType.groupPS) | ||
1289 | data.change = ObjectChangeType.primPS; | ||
1290 | part.StoreUndoState(data.change); // lets test only saving what we changed | ||
1291 | grp.doChangeObject(part, (ObjectChangeData)data); | ||
1292 | } | ||
1293 | else | ||
1294 | { | ||
1295 | // Is this any kind of group operation? | ||
1296 | if ((data.change & ObjectChangeType.Group) != 0) | ||
1297 | { | ||
1298 | // Is a move and/or rotation requested? | ||
1299 | if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0) | ||
1300 | { | ||
1301 | // Are we allowed to move it? | ||
1302 | if (m_parentScene.Permissions.CanMoveObject(grp.UUID, remoteClient.AgentId)) | ||
1303 | { | ||
1304 | // Strip all but move and rotation from request | ||
1305 | data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation); | ||
1306 | |||
1307 | part.StoreUndoState(data.change); | ||
1308 | grp.doChangeObject(part, (ObjectChangeData)data); | ||
1309 | } | ||
1310 | } | ||
1311 | } | ||
1312 | } | ||
1313 | } | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1190 | /// <summary> | 1317 | /// <summary> |
1191 | /// Update the scale of an individual prim. | 1318 | /// Update the scale of an individual prim. |
1192 | /// </summary> | 1319 | /// </summary> |
@@ -1201,7 +1328,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1201 | { | 1328 | { |
1202 | if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) | 1329 | if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) |
1203 | { | 1330 | { |
1331 | bool physbuild = false; | ||
1332 | if (part.ParentGroup.RootPart.PhysActor != null) | ||
1333 | { | ||
1334 | part.ParentGroup.RootPart.PhysActor.Building = true; | ||
1335 | physbuild = true; | ||
1336 | } | ||
1337 | |||
1204 | part.Resize(scale); | 1338 | part.Resize(scale); |
1339 | |||
1340 | if (physbuild) | ||
1341 | part.ParentGroup.RootPart.PhysActor.Building = false; | ||
1205 | } | 1342 | } |
1206 | } | 1343 | } |
1207 | } | 1344 | } |
@@ -1213,7 +1350,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1213 | { | 1350 | { |
1214 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1351 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) |
1215 | { | 1352 | { |
1353 | bool physbuild = false; | ||
1354 | if (group.RootPart.PhysActor != null) | ||
1355 | { | ||
1356 | group.RootPart.PhysActor.Building = true; | ||
1357 | physbuild = true; | ||
1358 | } | ||
1359 | |||
1216 | group.GroupResize(scale); | 1360 | group.GroupResize(scale); |
1361 | |||
1362 | if (physbuild) | ||
1363 | group.RootPart.PhysActor.Building = false; | ||
1217 | } | 1364 | } |
1218 | } | 1365 | } |
1219 | } | 1366 | } |
@@ -1341,8 +1488,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1341 | { | 1488 | { |
1342 | if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) | 1489 | if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) |
1343 | { | 1490 | { |
1344 | if (m_parentScene.AttachmentsModule != null) | 1491 | // Set the new attachment point data in the object |
1345 | m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); | 1492 | byte attachmentPoint = group.GetAttachmentPoint(); |
1493 | group.UpdateGroupPosition(pos); | ||
1494 | group.IsAttachment = false; | ||
1495 | group.AbsolutePosition = group.RootPart.AttachedPos; | ||
1496 | group.AttachmentPoint = attachmentPoint; | ||
1497 | group.HasGroupChanged = true; | ||
1346 | } | 1498 | } |
1347 | else | 1499 | else |
1348 | { | 1500 | { |
@@ -1390,7 +1542,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1390 | /// <param name="SetPhantom"></param> | 1542 | /// <param name="SetPhantom"></param> |
1391 | /// <param name="remoteClient"></param> | 1543 | /// <param name="remoteClient"></param> |
1392 | protected internal void UpdatePrimFlags( | 1544 | protected internal void UpdatePrimFlags( |
1393 | uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) | 1545 | uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient) |
1394 | { | 1546 | { |
1395 | SceneObjectGroup group = GetGroupByPrim(localID); | 1547 | SceneObjectGroup group = GetGroupByPrim(localID); |
1396 | if (group != null) | 1548 | if (group != null) |
@@ -1398,7 +1550,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
1398 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1550 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) |
1399 | { | 1551 | { |
1400 | // VolumeDetect can't be set via UI and will always be off when a change is made there | 1552 | // VolumeDetect can't be set via UI and will always be off when a change is made there |
1401 | group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); | 1553 | // now only change volume dtc if phantom off |
1554 | |||
1555 | if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data | ||
1556 | { | ||
1557 | bool vdtc; | ||
1558 | if (SetPhantom) // if phantom keep volumedtc | ||
1559 | vdtc = group.RootPart.VolumeDetectActive; | ||
1560 | else // else turn it off | ||
1561 | vdtc = false; | ||
1562 | |||
1563 | group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc); | ||
1564 | } | ||
1565 | else | ||
1566 | { | ||
1567 | SceneObjectPart part = GetSceneObjectPart(localID); | ||
1568 | if (part != null) | ||
1569 | { | ||
1570 | part.UpdateExtraPhysics(PhysData); | ||
1571 | if (part.UpdatePhysRequired) | ||
1572 | remoteClient.SendPartPhysicsProprieties(part); | ||
1573 | } | ||
1574 | } | ||
1402 | } | 1575 | } |
1403 | } | 1576 | } |
1404 | } | 1577 | } |
@@ -1542,6 +1715,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1542 | { | 1715 | { |
1543 | part.Material = Convert.ToByte(material); | 1716 | part.Material = Convert.ToByte(material); |
1544 | group.HasGroupChanged = true; | 1717 | group.HasGroupChanged = true; |
1718 | remoteClient.SendPartPhysicsProprieties(part); | ||
1545 | } | 1719 | } |
1546 | } | 1720 | } |
1547 | } | 1721 | } |
@@ -1606,6 +1780,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1606 | /// <param name="childPrims"></param> | 1780 | /// <param name="childPrims"></param> |
1607 | protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) | 1781 | protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) |
1608 | { | 1782 | { |
1783 | if (root.KeyframeMotion != null) | ||
1784 | { | ||
1785 | root.KeyframeMotion.Stop(); | ||
1786 | root.KeyframeMotion = null; | ||
1787 | } | ||
1788 | |||
1609 | SceneObjectGroup parentGroup = root.ParentGroup; | 1789 | SceneObjectGroup parentGroup = root.ParentGroup; |
1610 | if (parentGroup == null) return; | 1790 | if (parentGroup == null) return; |
1611 | 1791 | ||
@@ -1614,8 +1794,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1614 | return; | 1794 | return; |
1615 | 1795 | ||
1616 | Monitor.Enter(m_updateLock); | 1796 | Monitor.Enter(m_updateLock); |
1797 | |||
1617 | try | 1798 | try |
1618 | { | 1799 | { |
1800 | parentGroup.areUpdatesSuspended = true; | ||
1801 | |||
1619 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); | 1802 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); |
1620 | 1803 | ||
1621 | // We do this in reverse to get the link order of the prims correct | 1804 | // We do this in reverse to get the link order of the prims correct |
@@ -1630,9 +1813,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1630 | // Make sure no child prim is set for sale | 1813 | // Make sure no child prim is set for sale |
1631 | // So that, on delink, no prims are unwittingly | 1814 | // So that, on delink, no prims are unwittingly |
1632 | // left for sale and sold off | 1815 | // left for sale and sold off |
1633 | child.RootPart.ObjectSaleType = 0; | 1816 | |
1634 | child.RootPart.SalePrice = 10; | 1817 | if (child != null) |
1635 | childGroups.Add(child); | 1818 | { |
1819 | child.RootPart.ObjectSaleType = 0; | ||
1820 | child.RootPart.SalePrice = 10; | ||
1821 | childGroups.Add(child); | ||
1822 | } | ||
1636 | } | 1823 | } |
1637 | 1824 | ||
1638 | foreach (SceneObjectGroup child in childGroups) | 1825 | foreach (SceneObjectGroup child in childGroups) |
@@ -1659,6 +1846,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1659 | } | 1846 | } |
1660 | finally | 1847 | finally |
1661 | { | 1848 | { |
1849 | lock (SceneObjectGroupsByLocalPartID) | ||
1850 | { | ||
1851 | foreach (SceneObjectPart part in parentGroup.Parts) | ||
1852 | SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup; | ||
1853 | } | ||
1854 | |||
1855 | parentGroup.areUpdatesSuspended = false; | ||
1856 | parentGroup.HasGroupChanged = true; | ||
1857 | parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true); | ||
1858 | parentGroup.ScheduleGroupForFullUpdate(); | ||
1662 | Monitor.Exit(m_updateLock); | 1859 | Monitor.Exit(m_updateLock); |
1663 | } | 1860 | } |
1664 | } | 1861 | } |
@@ -1681,6 +1878,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1681 | { | 1878 | { |
1682 | if (part != null) | 1879 | if (part != null) |
1683 | { | 1880 | { |
1881 | if (part.KeyframeMotion != null) | ||
1882 | { | ||
1883 | part.KeyframeMotion.Stop(); | ||
1884 | part.KeyframeMotion = null; | ||
1885 | } | ||
1684 | if (part.ParentGroup.PrimCount != 1) // Skip single | 1886 | if (part.ParentGroup.PrimCount != 1) // Skip single |
1685 | { | 1887 | { |
1686 | if (part.LinkNum < 2) // Root | 1888 | if (part.LinkNum < 2) // Root |
@@ -1695,21 +1897,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
1695 | 1897 | ||
1696 | SceneObjectGroup group = part.ParentGroup; | 1898 | SceneObjectGroup group = part.ParentGroup; |
1697 | if (!affectedGroups.Contains(group)) | 1899 | if (!affectedGroups.Contains(group)) |
1900 | { | ||
1901 | group.areUpdatesSuspended = true; | ||
1698 | affectedGroups.Add(group); | 1902 | affectedGroups.Add(group); |
1903 | } | ||
1699 | } | 1904 | } |
1700 | } | 1905 | } |
1701 | } | 1906 | } |
1702 | 1907 | ||
1703 | foreach (SceneObjectPart child in childParts) | 1908 | if (childParts.Count > 0) |
1704 | { | 1909 | { |
1705 | // Unlink all child parts from their groups | 1910 | foreach (SceneObjectPart child in childParts) |
1706 | // | 1911 | { |
1707 | child.ParentGroup.DelinkFromGroup(child, true); | 1912 | // Unlink all child parts from their groups |
1708 | 1913 | // | |
1709 | // These are not in affected groups and will not be | 1914 | child.ParentGroup.DelinkFromGroup(child, true); |
1710 | // handled further. Do the honors here. | 1915 | child.ParentGroup.HasGroupChanged = true; |
1711 | child.ParentGroup.HasGroupChanged = true; | 1916 | child.ParentGroup.ScheduleGroupForFullUpdate(); |
1712 | child.ParentGroup.ScheduleGroupForFullUpdate(); | 1917 | } |
1713 | } | 1918 | } |
1714 | 1919 | ||
1715 | foreach (SceneObjectPart root in rootParts) | 1920 | foreach (SceneObjectPart root in rootParts) |
@@ -1719,56 +1924,68 @@ namespace OpenSim.Region.Framework.Scenes | |||
1719 | // However, editing linked parts and unlinking may be different | 1924 | // However, editing linked parts and unlinking may be different |
1720 | // | 1925 | // |
1721 | SceneObjectGroup group = root.ParentGroup; | 1926 | SceneObjectGroup group = root.ParentGroup; |
1927 | group.areUpdatesSuspended = true; | ||
1722 | 1928 | ||
1723 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); | 1929 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); |
1724 | int numChildren = newSet.Count; | 1930 | int numChildren = newSet.Count; |
1725 | 1931 | ||
1932 | if (numChildren == 1) | ||
1933 | break; | ||
1934 | |||
1726 | // If there are prims left in a link set, but the root is | 1935 | // If there are prims left in a link set, but the root is |
1727 | // slated for unlink, we need to do this | 1936 | // slated for unlink, we need to do this |
1937 | // Unlink the remaining set | ||
1728 | // | 1938 | // |
1729 | if (numChildren != 1) | 1939 | bool sendEventsToRemainder = true; |
1730 | { | 1940 | if (numChildren > 1) |
1731 | // Unlink the remaining set | 1941 | sendEventsToRemainder = false; |
1732 | // | ||
1733 | bool sendEventsToRemainder = true; | ||
1734 | if (numChildren > 1) | ||
1735 | sendEventsToRemainder = false; | ||
1736 | 1942 | ||
1737 | foreach (SceneObjectPart p in newSet) | 1943 | foreach (SceneObjectPart p in newSet) |
1944 | { | ||
1945 | if (p != group.RootPart) | ||
1738 | { | 1946 | { |
1739 | if (p != group.RootPart) | 1947 | group.DelinkFromGroup(p, sendEventsToRemainder); |
1740 | group.DelinkFromGroup(p, sendEventsToRemainder); | 1948 | if (numChildren > 2) |
1949 | { | ||
1950 | p.ParentGroup.areUpdatesSuspended = true; | ||
1951 | } | ||
1952 | else | ||
1953 | { | ||
1954 | p.ParentGroup.HasGroupChanged = true; | ||
1955 | p.ParentGroup.ScheduleGroupForFullUpdate(); | ||
1956 | } | ||
1741 | } | 1957 | } |
1958 | } | ||
1959 | |||
1960 | // If there is more than one prim remaining, we | ||
1961 | // need to re-link | ||
1962 | // | ||
1963 | if (numChildren > 2) | ||
1964 | { | ||
1965 | // Remove old root | ||
1966 | // | ||
1967 | if (newSet.Contains(root)) | ||
1968 | newSet.Remove(root); | ||
1742 | 1969 | ||
1743 | // If there is more than one prim remaining, we | 1970 | // Preserve link ordering |
1744 | // need to re-link | ||
1745 | // | 1971 | // |
1746 | if (numChildren > 2) | 1972 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) |
1747 | { | 1973 | { |
1748 | // Remove old root | 1974 | return a.LinkNum.CompareTo(b.LinkNum); |
1749 | // | 1975 | }); |
1750 | if (newSet.Contains(root)) | ||
1751 | newSet.Remove(root); | ||
1752 | |||
1753 | // Preserve link ordering | ||
1754 | // | ||
1755 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) | ||
1756 | { | ||
1757 | return a.LinkNum.CompareTo(b.LinkNum); | ||
1758 | }); | ||
1759 | 1976 | ||
1760 | // Determine new root | 1977 | // Determine new root |
1761 | // | 1978 | // |
1762 | SceneObjectPart newRoot = newSet[0]; | 1979 | SceneObjectPart newRoot = newSet[0]; |
1763 | newSet.RemoveAt(0); | 1980 | newSet.RemoveAt(0); |
1764 | 1981 | ||
1765 | foreach (SceneObjectPart newChild in newSet) | 1982 | foreach (SceneObjectPart newChild in newSet) |
1766 | newChild.ClearUpdateSchedule(); | 1983 | newChild.ClearUpdateSchedule(); |
1767 | 1984 | ||
1768 | LinkObjects(newRoot, newSet); | 1985 | newRoot.ParentGroup.areUpdatesSuspended = true; |
1769 | if (!affectedGroups.Contains(newRoot.ParentGroup)) | 1986 | LinkObjects(newRoot, newSet); |
1770 | affectedGroups.Add(newRoot.ParentGroup); | 1987 | if (!affectedGroups.Contains(newRoot.ParentGroup)) |
1771 | } | 1988 | affectedGroups.Add(newRoot.ParentGroup); |
1772 | } | 1989 | } |
1773 | } | 1990 | } |
1774 | 1991 | ||
@@ -1776,8 +1993,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1776 | // | 1993 | // |
1777 | foreach (SceneObjectGroup g in affectedGroups) | 1994 | foreach (SceneObjectGroup g in affectedGroups) |
1778 | { | 1995 | { |
1996 | // Child prims that have been unlinked and deleted will | ||
1997 | // return unless the root is deleted. This will remove them | ||
1998 | // from the database. They will be rewritten immediately, | ||
1999 | // minus the rows for the unlinked child prims. | ||
2000 | m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID); | ||
1779 | g.TriggerScriptChangedEvent(Changed.LINK); | 2001 | g.TriggerScriptChangedEvent(Changed.LINK); |
1780 | g.HasGroupChanged = true; // Persist | 2002 | g.HasGroupChanged = true; // Persist |
2003 | g.areUpdatesSuspended = false; | ||
1781 | g.ScheduleGroupForFullUpdate(); | 2004 | g.ScheduleGroupForFullUpdate(); |
1782 | } | 2005 | } |
1783 | } | 2006 | } |
@@ -1849,108 +2072,96 @@ namespace OpenSim.Region.Framework.Scenes | |||
1849 | /// <param name="GroupID"></param> | 2072 | /// <param name="GroupID"></param> |
1850 | /// <param name="rot"></param> | 2073 | /// <param name="rot"></param> |
1851 | /// <returns>null if duplication fails, otherwise the duplicated object</returns> | 2074 | /// <returns>null if duplication fails, otherwise the duplicated object</returns> |
1852 | public SceneObjectGroup DuplicateObject( | 2075 | /// <summary> |
1853 | uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) | 2076 | public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) |
1854 | { | 2077 | { |
1855 | Monitor.Enter(m_updateLock); | 2078 | // m_log.DebugFormat( |
2079 | // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", | ||
2080 | // originalPrimID, offset, AgentID); | ||
1856 | 2081 | ||
1857 | try | 2082 | SceneObjectGroup original = GetGroupByPrim(originalPrimID); |
2083 | if (original != null) | ||
1858 | { | 2084 | { |
1859 | // m_log.DebugFormat( | 2085 | if (m_parentScene.Permissions.CanDuplicateObject( |
1860 | // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", | 2086 | original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) |
1861 | // originalPrimID, offset, AgentID); | ||
1862 | |||
1863 | SceneObjectGroup original = GetGroupByPrim(originalPrimID); | ||
1864 | if (original == null) | ||
1865 | { | 2087 | { |
1866 | m_log.WarnFormat( | 2088 | SceneObjectGroup copy = original.Copy(true); |
1867 | "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); | 2089 | copy.AbsolutePosition = copy.AbsolutePosition + offset; |
1868 | 2090 | ||
1869 | return null; | 2091 | if (original.OwnerID != AgentID) |
1870 | } | 2092 | { |
2093 | copy.SetOwnerId(AgentID); | ||
2094 | copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID); | ||
1871 | 2095 | ||
1872 | if (!m_parentScene.Permissions.CanDuplicateObject( | 2096 | SceneObjectPart[] partList = copy.Parts; |
1873 | original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) | ||
1874 | return null; | ||
1875 | 2097 | ||
1876 | SceneObjectGroup copy = original.Copy(true); | 2098 | if (m_parentScene.Permissions.PropagatePermissions()) |
1877 | copy.AbsolutePosition = copy.AbsolutePosition + offset; | 2099 | { |
2100 | foreach (SceneObjectPart child in partList) | ||
2101 | { | ||
2102 | child.Inventory.ChangeInventoryOwner(AgentID); | ||
2103 | child.TriggerScriptChangedEvent(Changed.OWNER); | ||
2104 | child.ApplyNextOwnerPermissions(); | ||
2105 | } | ||
2106 | } | ||
2107 | } | ||
1878 | 2108 | ||
1879 | if (original.OwnerID != AgentID) | 2109 | // FIXME: This section needs to be refactored so that it just calls AddSceneObject() |
1880 | { | 2110 | Entities.Add(copy); |
1881 | copy.SetOwnerId(AgentID); | ||
1882 | copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID); | ||
1883 | 2111 | ||
1884 | SceneObjectPart[] partList = copy.Parts; | 2112 | lock (SceneObjectGroupsByFullID) |
2113 | SceneObjectGroupsByFullID[copy.UUID] = copy; | ||
1885 | 2114 | ||
1886 | if (m_parentScene.Permissions.PropagatePermissions()) | 2115 | SceneObjectPart[] children = copy.Parts; |
2116 | |||
2117 | lock (SceneObjectGroupsByFullPartID) | ||
1887 | { | 2118 | { |
1888 | foreach (SceneObjectPart child in partList) | 2119 | SceneObjectGroupsByFullPartID[copy.UUID] = copy; |
1889 | { | 2120 | foreach (SceneObjectPart part in children) |
1890 | child.Inventory.ChangeInventoryOwner(AgentID); | 2121 | SceneObjectGroupsByFullPartID[part.UUID] = copy; |
1891 | child.TriggerScriptChangedEvent(Changed.OWNER); | ||
1892 | child.ApplyNextOwnerPermissions(); | ||
1893 | } | ||
1894 | } | 2122 | } |
1895 | 2123 | ||
1896 | copy.RootPart.ObjectSaleType = 0; | 2124 | lock (SceneObjectGroupsByLocalPartID) |
1897 | copy.RootPart.SalePrice = 10; | 2125 | { |
1898 | } | 2126 | SceneObjectGroupsByLocalPartID[copy.LocalId] = copy; |
2127 | foreach (SceneObjectPart part in children) | ||
2128 | SceneObjectGroupsByLocalPartID[part.LocalId] = copy; | ||
2129 | } | ||
2130 | // PROBABLE END OF FIXME | ||
1899 | 2131 | ||
1900 | // FIXME: This section needs to be refactored so that it just calls AddSceneObject() | 2132 | // Since we copy from a source group that is in selected |
1901 | Entities.Add(copy); | 2133 | // state, but the copy is shown deselected in the viewer, |
1902 | 2134 | // We need to clear the selection flag here, else that | |
1903 | lock (SceneObjectGroupsByFullID) | 2135 | // prim never gets persisted at all. The client doesn't |
1904 | SceneObjectGroupsByFullID[copy.UUID] = copy; | 2136 | // think it's selected, so it will never send a deselect... |
1905 | 2137 | copy.IsSelected = false; | |
1906 | SceneObjectPart[] children = copy.Parts; | 2138 | |
1907 | 2139 | m_numPrim += copy.Parts.Length; | |
1908 | lock (SceneObjectGroupsByFullPartID) | 2140 | |
1909 | { | 2141 | if (rot != Quaternion.Identity) |
1910 | SceneObjectGroupsByFullPartID[copy.UUID] = copy; | 2142 | { |
1911 | foreach (SceneObjectPart part in children) | 2143 | copy.UpdateGroupRotationR(rot); |
1912 | SceneObjectGroupsByFullPartID[part.UUID] = copy; | 2144 | } |
1913 | } | ||
1914 | |||
1915 | lock (SceneObjectGroupsByLocalPartID) | ||
1916 | { | ||
1917 | SceneObjectGroupsByLocalPartID[copy.LocalId] = copy; | ||
1918 | foreach (SceneObjectPart part in children) | ||
1919 | SceneObjectGroupsByLocalPartID[part.LocalId] = copy; | ||
1920 | } | ||
1921 | // PROBABLE END OF FIXME | ||
1922 | |||
1923 | // Since we copy from a source group that is in selected | ||
1924 | // state, but the copy is shown deselected in the viewer, | ||
1925 | // We need to clear the selection flag here, else that | ||
1926 | // prim never gets persisted at all. The client doesn't | ||
1927 | // think it's selected, so it will never send a deselect... | ||
1928 | copy.IsSelected = false; | ||
1929 | |||
1930 | m_numPrim += copy.Parts.Length; | ||
1931 | |||
1932 | if (rot != Quaternion.Identity) | ||
1933 | { | ||
1934 | copy.UpdateGroupRotationR(rot); | ||
1935 | } | ||
1936 | 2145 | ||
1937 | copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); | 2146 | copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); |
1938 | copy.HasGroupChanged = true; | 2147 | copy.HasGroupChanged = true; |
1939 | copy.ScheduleGroupForFullUpdate(); | 2148 | copy.ScheduleGroupForFullUpdate(); |
1940 | copy.ResumeScripts(); | 2149 | copy.ResumeScripts(); |
1941 | 2150 | ||
1942 | // required for physics to update it's position | 2151 | // required for physics to update it's position |
1943 | copy.AbsolutePosition = copy.AbsolutePosition; | 2152 | copy.AbsolutePosition = copy.AbsolutePosition; |
1944 | 2153 | ||
1945 | return copy; | 2154 | return copy; |
2155 | } | ||
1946 | } | 2156 | } |
1947 | finally | 2157 | else |
1948 | { | 2158 | { |
1949 | Monitor.Exit(m_updateLock); | 2159 | m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID); |
1950 | } | 2160 | } |
2161 | |||
2162 | return null; | ||
1951 | } | 2163 | } |
1952 | 2164 | ||
1953 | /// <summary> | ||
1954 | /// Calculates the distance between two Vector3s | 2165 | /// Calculates the distance between two Vector3s |
1955 | /// </summary> | 2166 | /// </summary> |
1956 | /// <param name="v1"></param> | 2167 | /// <param name="v1"></param> |