diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rwxr-xr-x | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 542 |
1 files changed, 364 insertions, 178 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index e0080f2..0879cce 100755 --- 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 | ||
@@ -134,13 +144,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
134 | 144 | ||
135 | protected internal void Close() | 145 | protected internal void Close() |
136 | { | 146 | { |
137 | lock (m_presenceLock) | 147 | m_scenePresencesLock.EnterWriteLock(); |
148 | try | ||
138 | { | 149 | { |
139 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); | 150 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); |
140 | List<ScenePresence> newlist = new List<ScenePresence>(); | 151 | List<ScenePresence> newlist = new List<ScenePresence>(); |
141 | m_scenePresenceMap = newmap; | 152 | m_scenePresenceMap = newmap; |
142 | m_scenePresenceArray = newlist; | 153 | m_scenePresenceArray = newlist; |
143 | } | 154 | } |
155 | finally | ||
156 | { | ||
157 | m_scenePresencesLock.ExitWriteLock(); | ||
158 | } | ||
144 | 159 | ||
145 | lock (SceneObjectGroupsByFullID) | 160 | lock (SceneObjectGroupsByFullID) |
146 | SceneObjectGroupsByFullID.Clear(); | 161 | SceneObjectGroupsByFullID.Clear(); |
@@ -207,6 +222,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
207 | return PhysicsScene.Simulate((float)elapsed); | 222 | return PhysicsScene.Simulate((float)elapsed); |
208 | } | 223 | } |
209 | 224 | ||
225 | protected internal void ProcessPhysicsPreSimulation() | ||
226 | { | ||
227 | if(PhysicsScene != null) | ||
228 | PhysicsScene.ProcessPreSimulation(); | ||
229 | } | ||
230 | |||
210 | protected internal void UpdateScenePresenceMovement() | 231 | protected internal void UpdateScenePresenceMovement() |
211 | { | 232 | { |
212 | ForEachScenePresence(delegate(ScenePresence presence) | 233 | ForEachScenePresence(delegate(ScenePresence presence) |
@@ -261,13 +282,54 @@ namespace OpenSim.Region.Framework.Scenes | |||
261 | protected internal bool AddRestoredSceneObject( | 282 | protected internal bool AddRestoredSceneObject( |
262 | SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) | 283 | SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) |
263 | { | 284 | { |
285 | if (!m_parentScene.CombineRegions) | ||
286 | { | ||
287 | // temporary checks to remove after varsize suport | ||
288 | float regionSizeX = m_parentScene.RegionInfo.RegionSizeX; | ||
289 | if (regionSizeX == 0) | ||
290 | regionSizeX = Constants.RegionSize; | ||
291 | float regionSizeY = m_parentScene.RegionInfo.RegionSizeY; | ||
292 | if (regionSizeY == 0) | ||
293 | regionSizeY = Constants.RegionSize; | ||
294 | |||
295 | // KF: Check for out-of-region, move inside and make static. | ||
296 | Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X, | ||
297 | sceneObject.RootPart.GroupPosition.Y, | ||
298 | sceneObject.RootPart.GroupPosition.Z); | ||
299 | 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 || | ||
300 | npos.X > regionSizeX || | ||
301 | npos.Y > regionSizeY)) | ||
302 | { | ||
303 | if (npos.X < 0.0) npos.X = 1.0f; | ||
304 | if (npos.Y < 0.0) npos.Y = 1.0f; | ||
305 | if (npos.Z < 0.0) npos.Z = 0.0f; | ||
306 | if (npos.X > regionSizeX) npos.X = regionSizeX - 1.0f; | ||
307 | if (npos.Y > regionSizeY) npos.Y = regionSizeY - 1.0f; | ||
308 | |||
309 | SceneObjectPart rootpart = sceneObject.RootPart; | ||
310 | rootpart.GroupPosition = npos; | ||
311 | |||
312 | foreach (SceneObjectPart part in sceneObject.Parts) | ||
313 | { | ||
314 | if (part == rootpart) | ||
315 | continue; | ||
316 | part.GroupPosition = npos; | ||
317 | } | ||
318 | rootpart.Velocity = Vector3.Zero; | ||
319 | rootpart.AngularVelocity = Vector3.Zero; | ||
320 | rootpart.Acceleration = Vector3.Zero; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); | ||
325 | |||
264 | if (attachToBackup && (!alreadyPersisted)) | 326 | if (attachToBackup && (!alreadyPersisted)) |
265 | { | 327 | { |
266 | sceneObject.ForceInventoryPersistence(); | 328 | sceneObject.ForceInventoryPersistence(); |
267 | sceneObject.HasGroupChanged = true; | 329 | sceneObject.HasGroupChanged = true; |
268 | } | 330 | } |
269 | 331 | ||
270 | return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); | 332 | return ret; |
271 | } | 333 | } |
272 | 334 | ||
273 | /// <summary> | 335 | /// <summary> |
@@ -284,12 +346,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
284 | /// </returns> | 346 | /// </returns> |
285 | protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) | 347 | protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) |
286 | { | 348 | { |
287 | // Ensure that we persist this new scene object if it's not an | 349 | |
350 | bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); | ||
351 | |||
352 | // Ensure that we persist this new scene object if it's not an | ||
288 | // attachment | 353 | // attachment |
354 | |||
289 | if (attachToBackup) | 355 | if (attachToBackup) |
290 | sceneObject.HasGroupChanged = true; | 356 | sceneObject.HasGroupChanged = true; |
291 | 357 | ||
292 | return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); | 358 | return ret; |
293 | } | 359 | } |
294 | 360 | ||
295 | /// <summary> | 361 | /// <summary> |
@@ -324,9 +390,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
324 | if (pa != null && pa.IsPhysical && vel != Vector3.Zero) | 390 | if (pa != null && pa.IsPhysical && vel != Vector3.Zero) |
325 | { | 391 | { |
326 | sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false); | 392 | sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false); |
327 | sceneObject.Velocity = vel; | ||
328 | } | 393 | } |
329 | 394 | ||
330 | return true; | 395 | return true; |
331 | } | 396 | } |
332 | 397 | ||
@@ -351,6 +416,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
351 | /// </returns> | 416 | /// </returns> |
352 | protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) | 417 | protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) |
353 | { | 418 | { |
419 | if (sceneObject == null) | ||
420 | { | ||
421 | m_log.ErrorFormat("[SCENEGRAPH]: Tried to add null scene object"); | ||
422 | return false; | ||
423 | } | ||
354 | if (sceneObject.UUID == UUID.Zero) | 424 | if (sceneObject.UUID == UUID.Zero) |
355 | { | 425 | { |
356 | m_log.ErrorFormat( | 426 | m_log.ErrorFormat( |
@@ -383,9 +453,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
383 | { | 453 | { |
384 | Vector3 scale = part.Shape.Scale; | 454 | Vector3 scale = part.Shape.Scale; |
385 | 455 | ||
386 | scale.X = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.X)); | 456 | scale.X = Util.Clamp(scale.X, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys); |
387 | scale.Y = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Y)); | 457 | scale.Y = Util.Clamp(scale.Y, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys); |
388 | scale.Z = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Z)); | 458 | scale.Z = Util.Clamp(scale.Z, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys); |
389 | 459 | ||
390 | part.Shape.Scale = scale; | 460 | part.Shape.Scale = scale; |
391 | } | 461 | } |
@@ -406,36 +476,39 @@ namespace OpenSim.Region.Framework.Scenes | |||
406 | 476 | ||
407 | sceneObject.AttachToScene(m_parentScene); | 477 | sceneObject.AttachToScene(m_parentScene); |
408 | 478 | ||
409 | if (sendClientUpdates) | ||
410 | sceneObject.ScheduleGroupForFullUpdate(); | ||
411 | |||
412 | Entities.Add(sceneObject); | 479 | Entities.Add(sceneObject); |
413 | 480 | ||
414 | if (attachToBackup) | ||
415 | sceneObject.AttachToBackup(); | ||
416 | |||
417 | lock (SceneObjectGroupsByFullID) | 481 | lock (SceneObjectGroupsByFullID) |
418 | SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; | 482 | SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; |
419 | 483 | ||
420 | lock (SceneObjectGroupsByFullPartID) | 484 | foreach (SceneObjectPart part in parts) |
421 | { | 485 | { |
422 | foreach (SceneObjectPart part in parts) | 486 | lock (SceneObjectGroupsByFullPartID) |
423 | SceneObjectGroupsByFullPartID[part.UUID] = sceneObject; | 487 | SceneObjectGroupsByFullPartID[part.UUID] = sceneObject; |
424 | } | ||
425 | |||
426 | lock (SceneObjectGroupsByLocalPartID) | ||
427 | { | ||
428 | // m_log.DebugFormat( | ||
429 | // "[SCENE GRAPH]: Adding scene object {0} {1} {2} to SceneObjectGroupsByLocalPartID in {3}", | ||
430 | // sceneObject.Name, sceneObject.UUID, sceneObject.LocalId, m_parentScene.RegionInfo.RegionName); | ||
431 | 488 | ||
432 | foreach (SceneObjectPart part in parts) | 489 | lock (SceneObjectGroupsByLocalPartID) |
433 | SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject; | 490 | SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject; |
434 | } | 491 | } |
435 | 492 | ||
493 | if (sendClientUpdates) | ||
494 | sceneObject.ScheduleGroupForFullUpdate(); | ||
495 | |||
496 | if (attachToBackup) | ||
497 | sceneObject.AttachToBackup(); | ||
498 | |||
436 | return true; | 499 | return true; |
437 | } | 500 | } |
438 | 501 | ||
502 | public void updateScenePartGroup(SceneObjectPart part, SceneObjectGroup grp) | ||
503 | { | ||
504 | // no tests, caller has responsability... | ||
505 | lock (SceneObjectGroupsByFullPartID) | ||
506 | SceneObjectGroupsByFullPartID[part.UUID] = grp; | ||
507 | |||
508 | lock (SceneObjectGroupsByLocalPartID) | ||
509 | SceneObjectGroupsByLocalPartID[part.LocalId] = grp; | ||
510 | } | ||
511 | |||
439 | /// <summary> | 512 | /// <summary> |
440 | /// Delete an object from the scene | 513 | /// Delete an object from the scene |
441 | /// </summary> | 514 | /// </summary> |
@@ -476,25 +549,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
476 | if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) | 549 | if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) |
477 | RemovePhysicalPrim(grp.PrimCount); | 550 | RemovePhysicalPrim(grp.PrimCount); |
478 | } | 551 | } |
479 | 552 | ||
553 | bool ret = Entities.Remove(uuid); | ||
554 | |||
480 | lock (SceneObjectGroupsByFullID) | 555 | lock (SceneObjectGroupsByFullID) |
481 | SceneObjectGroupsByFullID.Remove(grp.UUID); | 556 | SceneObjectGroupsByFullID.Remove(grp.UUID); |
482 | 557 | ||
483 | lock (SceneObjectGroupsByFullPartID) | 558 | SceneObjectPart[] parts = grp.Parts; |
559 | for (int i = 0; i < parts.Length; i++) | ||
484 | { | 560 | { |
485 | SceneObjectPart[] parts = grp.Parts; | 561 | lock (SceneObjectGroupsByFullPartID) |
486 | for (int i = 0; i < parts.Length; i++) | ||
487 | SceneObjectGroupsByFullPartID.Remove(parts[i].UUID); | 562 | SceneObjectGroupsByFullPartID.Remove(parts[i].UUID); |
488 | } | ||
489 | 563 | ||
490 | lock (SceneObjectGroupsByLocalPartID) | 564 | lock (SceneObjectGroupsByLocalPartID) |
491 | { | ||
492 | SceneObjectPart[] parts = grp.Parts; | ||
493 | for (int i = 0; i < parts.Length; i++) | ||
494 | SceneObjectGroupsByLocalPartID.Remove(parts[i].LocalId); | 565 | SceneObjectGroupsByLocalPartID.Remove(parts[i].LocalId); |
495 | } | 566 | } |
496 | 567 | ||
497 | return Entities.Remove(uuid); | 568 | return ret; |
498 | } | 569 | } |
499 | 570 | ||
500 | /// <summary> | 571 | /// <summary> |
@@ -509,6 +580,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
509 | m_updateList[obj.UUID] = obj; | 580 | m_updateList[obj.UUID] = obj; |
510 | } | 581 | } |
511 | 582 | ||
583 | public void FireAttachToBackup(SceneObjectGroup obj) | ||
584 | { | ||
585 | if (OnAttachToBackup != null) | ||
586 | { | ||
587 | OnAttachToBackup(obj); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | public void FireDetachFromBackup(SceneObjectGroup obj) | ||
592 | { | ||
593 | if (OnDetachFromBackup != null) | ||
594 | { | ||
595 | OnDetachFromBackup(obj); | ||
596 | } | ||
597 | } | ||
598 | |||
599 | public void FireChangeBackup(SceneObjectGroup obj) | ||
600 | { | ||
601 | if (OnChangeBackup != null) | ||
602 | { | ||
603 | OnChangeBackup(obj); | ||
604 | } | ||
605 | } | ||
606 | |||
512 | /// <summary> | 607 | /// <summary> |
513 | /// Process all pending updates | 608 | /// Process all pending updates |
514 | /// </summary> | 609 | /// </summary> |
@@ -600,7 +695,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
600 | 695 | ||
601 | Entities[presence.UUID] = presence; | 696 | Entities[presence.UUID] = presence; |
602 | 697 | ||
603 | lock (m_presenceLock) | 698 | m_scenePresencesLock.EnterWriteLock(); |
699 | try | ||
604 | { | 700 | { |
605 | m_numChildAgents++; | 701 | m_numChildAgents++; |
606 | 702 | ||
@@ -626,6 +722,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
626 | m_scenePresenceMap = newmap; | 722 | m_scenePresenceMap = newmap; |
627 | m_scenePresenceArray = newlist; | 723 | m_scenePresenceArray = newlist; |
628 | } | 724 | } |
725 | finally | ||
726 | { | ||
727 | m_scenePresencesLock.ExitWriteLock(); | ||
728 | } | ||
629 | 729 | ||
630 | return presence; | 730 | return presence; |
631 | } | 731 | } |
@@ -642,7 +742,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
642 | agentID); | 742 | agentID); |
643 | } | 743 | } |
644 | 744 | ||
645 | lock (m_presenceLock) | 745 | m_scenePresencesLock.EnterWriteLock(); |
746 | try | ||
646 | { | 747 | { |
647 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); | 748 | Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); |
648 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); | 749 | List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); |
@@ -664,6 +765,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
664 | m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); | 765 | m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); |
665 | } | 766 | } |
666 | } | 767 | } |
768 | finally | ||
769 | { | ||
770 | m_scenePresencesLock.ExitWriteLock(); | ||
771 | } | ||
667 | } | 772 | } |
668 | 773 | ||
669 | protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) | 774 | protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) |
@@ -892,7 +997,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
892 | m_log.WarnFormat( | 997 | m_log.WarnFormat( |
893 | "[SCENE GRAPH]: Found scene object {0} {1} {2} via SceneObjectGroupsByLocalPartID index but it doesn't contain part with local id {3}. Removing from entry from index in {4}.", | 998 | "[SCENE GRAPH]: Found scene object {0} {1} {2} via SceneObjectGroupsByLocalPartID index but it doesn't contain part with local id {3}. Removing from entry from index in {4}.", |
894 | sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName); | 999 | sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName); |
895 | 1000 | m_log.WarnFormat("stack: {0}", Environment.StackTrace); | |
896 | SceneObjectGroupsByLocalPartID.Remove(localID); | 1001 | SceneObjectGroupsByLocalPartID.Remove(localID); |
897 | } | 1002 | } |
898 | } | 1003 | } |
@@ -1228,6 +1333,52 @@ namespace OpenSim.Region.Framework.Scenes | |||
1228 | 1333 | ||
1229 | #region Client Event handlers | 1334 | #region Client Event handlers |
1230 | 1335 | ||
1336 | protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient) | ||
1337 | { | ||
1338 | SceneObjectPart part = GetSceneObjectPart(localID); | ||
1339 | ObjectChangeData data = (ObjectChangeData)odata; | ||
1340 | |||
1341 | if (part != null) | ||
1342 | { | ||
1343 | SceneObjectGroup grp = part.ParentGroup; | ||
1344 | if (grp != null) | ||
1345 | { | ||
1346 | if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId)) | ||
1347 | { | ||
1348 | // These two are exceptions SL makes in the interpretation | ||
1349 | // of the change flags. Must check them here because otherwise | ||
1350 | // the group flag (see below) would be lost | ||
1351 | if (data.change == ObjectChangeType.groupS) | ||
1352 | data.change = ObjectChangeType.primS; | ||
1353 | if (data.change == ObjectChangeType.groupPS) | ||
1354 | data.change = ObjectChangeType.primPS; | ||
1355 | part.StoreUndoState(data.change); // lets test only saving what we changed | ||
1356 | grp.doChangeObject(part, (ObjectChangeData)data); | ||
1357 | } | ||
1358 | else | ||
1359 | { | ||
1360 | // Is this any kind of group operation? | ||
1361 | if ((data.change & ObjectChangeType.Group) != 0) | ||
1362 | { | ||
1363 | // Is a move and/or rotation requested? | ||
1364 | if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0) | ||
1365 | { | ||
1366 | // Are we allowed to move it? | ||
1367 | if (m_parentScene.Permissions.CanMoveObject(grp.UUID, remoteClient.AgentId)) | ||
1368 | { | ||
1369 | // Strip all but move and rotation from request | ||
1370 | data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation); | ||
1371 | |||
1372 | part.StoreUndoState(data.change); | ||
1373 | grp.doChangeObject(part, (ObjectChangeData)data); | ||
1374 | } | ||
1375 | } | ||
1376 | } | ||
1377 | } | ||
1378 | } | ||
1379 | } | ||
1380 | } | ||
1381 | |||
1231 | /// <summary> | 1382 | /// <summary> |
1232 | /// Update the scale of an individual prim. | 1383 | /// Update the scale of an individual prim. |
1233 | /// </summary> | 1384 | /// </summary> |
@@ -1242,7 +1393,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1242 | { | 1393 | { |
1243 | if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) | 1394 | if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) |
1244 | { | 1395 | { |
1396 | bool physbuild = false; | ||
1397 | if (part.ParentGroup.RootPart.PhysActor != null) | ||
1398 | { | ||
1399 | part.ParentGroup.RootPart.PhysActor.Building = true; | ||
1400 | physbuild = true; | ||
1401 | } | ||
1402 | |||
1245 | part.Resize(scale); | 1403 | part.Resize(scale); |
1404 | |||
1405 | if (physbuild) | ||
1406 | part.ParentGroup.RootPart.PhysActor.Building = false; | ||
1246 | } | 1407 | } |
1247 | } | 1408 | } |
1248 | } | 1409 | } |
@@ -1254,7 +1415,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1254 | { | 1415 | { |
1255 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) | 1416 | if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) |
1256 | { | 1417 | { |
1418 | bool physbuild = false; | ||
1419 | if (group.RootPart.PhysActor != null) | ||
1420 | { | ||
1421 | group.RootPart.PhysActor.Building = true; | ||
1422 | physbuild = true; | ||
1423 | } | ||
1424 | |||
1257 | group.GroupResize(scale); | 1425 | group.GroupResize(scale); |
1426 | |||
1427 | if (physbuild) | ||
1428 | group.RootPart.PhysActor.Building = false; | ||
1258 | } | 1429 | } |
1259 | } | 1430 | } |
1260 | } | 1431 | } |
@@ -1393,8 +1564,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1393 | { | 1564 | { |
1394 | if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) | 1565 | if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) |
1395 | { | 1566 | { |
1396 | if (m_parentScene.AttachmentsModule != null) | 1567 | // Set the new attachment point data in the object |
1397 | m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); | 1568 | byte attachmentPoint = group.GetAttachmentPoint(); |
1569 | group.UpdateGroupPosition(pos); | ||
1570 | group.IsAttachment = false; | ||
1571 | group.AbsolutePosition = group.RootPart.AttachedPos; | ||
1572 | group.AttachmentPoint = attachmentPoint; | ||
1573 | group.HasGroupChanged = true; | ||
1398 | } | 1574 | } |
1399 | else | 1575 | else |
1400 | { | 1576 | { |
@@ -1452,6 +1628,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1452 | // VolumeDetect can't be set via UI and will always be off when a change is made there | 1628 | // VolumeDetect can't be set via UI and will always be off when a change is made there |
1453 | // now only change volume dtc if phantom off | 1629 | // now only change volume dtc if phantom off |
1454 | 1630 | ||
1631 | bool wantedPhys = UsePhysics; | ||
1455 | if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data | 1632 | if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data |
1456 | { | 1633 | { |
1457 | bool vdtc; | 1634 | bool vdtc; |
@@ -1468,10 +1645,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1468 | if (part != null) | 1645 | if (part != null) |
1469 | { | 1646 | { |
1470 | part.UpdateExtraPhysics(PhysData); | 1647 | part.UpdateExtraPhysics(PhysData); |
1471 | if (part.UpdatePhysRequired) | 1648 | if (part.UpdatePhysRequired && remoteClient != null) |
1472 | remoteClient.SendPartPhysicsProprieties(part); | 1649 | remoteClient.SendPartPhysicsProprieties(part); |
1473 | } | 1650 | } |
1474 | } | 1651 | } |
1652 | |||
1653 | if (wantedPhys != group.UsesPhysics && remoteClient != null) | ||
1654 | { | ||
1655 | remoteClient.SendAlertMessage("Object physics canceled because exceeds the limit of " + | ||
1656 | m_parentScene.m_linksetPhysCapacity + " physical prims with shape type not set to None"); | ||
1657 | group.RootPart.ScheduleFullUpdate(); | ||
1658 | } | ||
1475 | } | 1659 | } |
1476 | } | 1660 | } |
1477 | } | 1661 | } |
@@ -1616,6 +1800,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1616 | { | 1800 | { |
1617 | part.Material = Convert.ToByte(material); | 1801 | part.Material = Convert.ToByte(material); |
1618 | group.HasGroupChanged = true; | 1802 | group.HasGroupChanged = true; |
1803 | remoteClient.SendPartPhysicsProprieties(part); | ||
1619 | } | 1804 | } |
1620 | } | 1805 | } |
1621 | } | 1806 | } |
@@ -1694,12 +1879,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1694 | return; | 1879 | return; |
1695 | 1880 | ||
1696 | Monitor.Enter(m_updateLock); | 1881 | Monitor.Enter(m_updateLock); |
1882 | |||
1697 | try | 1883 | try |
1698 | { | 1884 | { |
1885 | |||
1699 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); | 1886 | List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); |
1700 | 1887 | ||
1701 | // We do this in reverse to get the link order of the prims correct | 1888 | // We do this in reverse to get the link order of the prims correct |
1702 | for (int i = 0 ; i < children.Count ; i++) | 1889 | for (int i = 0; i < children.Count; i++) |
1703 | { | 1890 | { |
1704 | SceneObjectGroup child = children[i].ParentGroup; | 1891 | SceneObjectGroup child = children[i].ParentGroup; |
1705 | 1892 | ||
@@ -1710,9 +1897,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1710 | // Make sure no child prim is set for sale | 1897 | // Make sure no child prim is set for sale |
1711 | // So that, on delink, no prims are unwittingly | 1898 | // So that, on delink, no prims are unwittingly |
1712 | // left for sale and sold off | 1899 | // left for sale and sold off |
1713 | child.RootPart.ObjectSaleType = 0; | 1900 | |
1714 | child.RootPart.SalePrice = 10; | 1901 | if (child != null) |
1715 | childGroups.Add(child); | 1902 | { |
1903 | child.RootPart.ObjectSaleType = 0; | ||
1904 | child.RootPart.SalePrice = 10; | ||
1905 | childGroups.Add(child); | ||
1906 | } | ||
1716 | } | 1907 | } |
1717 | 1908 | ||
1718 | foreach (SceneObjectGroup child in childGroups) | 1909 | foreach (SceneObjectGroup child in childGroups) |
@@ -1741,6 +1932,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1741 | } | 1932 | } |
1742 | finally | 1933 | finally |
1743 | { | 1934 | { |
1935 | /* | ||
1936 | lock (SceneObjectGroupsByLocalPartID) | ||
1937 | { | ||
1938 | foreach (SceneObjectPart part in parentGroup.Parts) | ||
1939 | SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup; | ||
1940 | } | ||
1941 | */ | ||
1942 | parentGroup.AdjustChildPrimPermissions(false); | ||
1943 | parentGroup.HasGroupChanged = true; | ||
1944 | parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true); | ||
1945 | parentGroup.ScheduleGroupForFullUpdate(); | ||
1744 | Monitor.Exit(m_updateLock); | 1946 | Monitor.Exit(m_updateLock); |
1745 | } | 1947 | } |
1746 | } | 1948 | } |
@@ -1782,21 +1984,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
1782 | 1984 | ||
1783 | SceneObjectGroup group = part.ParentGroup; | 1985 | SceneObjectGroup group = part.ParentGroup; |
1784 | if (!affectedGroups.Contains(group)) | 1986 | if (!affectedGroups.Contains(group)) |
1987 | { | ||
1785 | affectedGroups.Add(group); | 1988 | affectedGroups.Add(group); |
1989 | } | ||
1786 | } | 1990 | } |
1787 | } | 1991 | } |
1788 | } | 1992 | } |
1789 | 1993 | ||
1790 | foreach (SceneObjectPart child in childParts) | 1994 | if (childParts.Count > 0) |
1791 | { | 1995 | { |
1792 | // Unlink all child parts from their groups | 1996 | foreach (SceneObjectPart child in childParts) |
1793 | // | 1997 | { |
1794 | child.ParentGroup.DelinkFromGroup(child, true); | 1998 | // Unlink all child parts from their groups |
1795 | 1999 | // | |
1796 | // These are not in affected groups and will not be | 2000 | child.ParentGroup.DelinkFromGroup(child, true); |
1797 | // handled further. Do the honors here. | 2001 | child.ParentGroup.HasGroupChanged = true; |
1798 | child.ParentGroup.HasGroupChanged = true; | 2002 | child.ParentGroup.ScheduleGroupForFullUpdate(); |
1799 | child.ParentGroup.ScheduleGroupForFullUpdate(); | 2003 | } |
1800 | } | 2004 | } |
1801 | 2005 | ||
1802 | foreach (SceneObjectPart root in rootParts) | 2006 | foreach (SceneObjectPart root in rootParts) |
@@ -1810,52 +2014,58 @@ namespace OpenSim.Region.Framework.Scenes | |||
1810 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); | 2014 | List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); |
1811 | int numChildren = newSet.Count; | 2015 | int numChildren = newSet.Count; |
1812 | 2016 | ||
2017 | if (numChildren == 1) | ||
2018 | break; | ||
2019 | |||
1813 | // If there are prims left in a link set, but the root is | 2020 | // If there are prims left in a link set, but the root is |
1814 | // slated for unlink, we need to do this | 2021 | // slated for unlink, we need to do this |
2022 | // Unlink the remaining set | ||
1815 | // | 2023 | // |
1816 | if (numChildren != 1) | 2024 | bool sendEventsToRemainder = false; |
1817 | { | 2025 | if (numChildren == 2) // only one child prim no re-link needed |
1818 | // Unlink the remaining set | 2026 | sendEventsToRemainder = true; |
1819 | // | ||
1820 | bool sendEventsToRemainder = true; | ||
1821 | if (numChildren > 1) | ||
1822 | sendEventsToRemainder = false; | ||
1823 | 2027 | ||
1824 | foreach (SceneObjectPart p in newSet) | 2028 | foreach (SceneObjectPart p in newSet) |
2029 | { | ||
2030 | if (p != group.RootPart) | ||
1825 | { | 2031 | { |
1826 | if (p != group.RootPart) | 2032 | group.DelinkFromGroup(p, sendEventsToRemainder); |
1827 | group.DelinkFromGroup(p, sendEventsToRemainder); | 2033 | if (sendEventsToRemainder) // finish single child prim now |
2034 | { | ||
2035 | p.ParentGroup.HasGroupChanged = true; | ||
2036 | p.ParentGroup.ScheduleGroupForFullUpdate(); | ||
2037 | } | ||
1828 | } | 2038 | } |
2039 | } | ||
2040 | |||
2041 | // If there is more than one prim remaining, we | ||
2042 | // need to re-link | ||
2043 | // | ||
2044 | if (numChildren > 2) | ||
2045 | { | ||
2046 | // Remove old root | ||
2047 | // | ||
2048 | if (newSet.Contains(root)) | ||
2049 | newSet.Remove(root); | ||
1829 | 2050 | ||
1830 | // If there is more than one prim remaining, we | 2051 | // Preserve link ordering |
1831 | // need to re-link | ||
1832 | // | 2052 | // |
1833 | if (numChildren > 2) | 2053 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) |
1834 | { | 2054 | { |
1835 | // Remove old root | 2055 | return a.LinkNum.CompareTo(b.LinkNum); |
1836 | // | 2056 | }); |
1837 | if (newSet.Contains(root)) | ||
1838 | newSet.Remove(root); | ||
1839 | |||
1840 | // Preserve link ordering | ||
1841 | // | ||
1842 | newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) | ||
1843 | { | ||
1844 | return a.LinkNum.CompareTo(b.LinkNum); | ||
1845 | }); | ||
1846 | 2057 | ||
1847 | // Determine new root | 2058 | // Determine new root |
1848 | // | 2059 | // |
1849 | SceneObjectPart newRoot = newSet[0]; | 2060 | SceneObjectPart newRoot = newSet[0]; |
1850 | newSet.RemoveAt(0); | 2061 | newSet.RemoveAt(0); |
1851 | 2062 | ||
1852 | foreach (SceneObjectPart newChild in newSet) | 2063 | foreach (SceneObjectPart newChild in newSet) |
1853 | newChild.ClearUpdateSchedule(); | 2064 | newChild.ClearUpdateSchedule(); |
1854 | 2065 | ||
1855 | LinkObjects(newRoot, newSet); | 2066 | LinkObjects(newRoot, newSet); |
1856 | if (!affectedGroups.Contains(newRoot.ParentGroup)) | 2067 | // if (!affectedGroups.Contains(newRoot.ParentGroup)) |
1857 | affectedGroups.Add(newRoot.ParentGroup); | 2068 | // affectedGroups.Add(newRoot.ParentGroup); |
1858 | } | ||
1859 | } | 2069 | } |
1860 | } | 2070 | } |
1861 | 2071 | ||
@@ -1863,6 +2073,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1863 | // | 2073 | // |
1864 | foreach (SceneObjectGroup g in affectedGroups) | 2074 | foreach (SceneObjectGroup g in affectedGroups) |
1865 | { | 2075 | { |
2076 | // Child prims that have been unlinked and deleted will | ||
2077 | // return unless the root is deleted. This will remove them | ||
2078 | // from the database. They will be rewritten immediately, | ||
2079 | // minus the rows for the unlinked child prims. | ||
2080 | g.AdjustChildPrimPermissions(false); | ||
2081 | m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID); | ||
1866 | g.TriggerScriptChangedEvent(Changed.LINK); | 2082 | g.TriggerScriptChangedEvent(Changed.LINK); |
1867 | g.HasGroupChanged = true; // Persist | 2083 | g.HasGroupChanged = true; // Persist |
1868 | g.ScheduleGroupForFullUpdate(); | 2084 | g.ScheduleGroupForFullUpdate(); |
@@ -1936,120 +2152,90 @@ namespace OpenSim.Region.Framework.Scenes | |||
1936 | /// <param name="GroupID"></param> | 2152 | /// <param name="GroupID"></param> |
1937 | /// <param name="rot"></param> | 2153 | /// <param name="rot"></param> |
1938 | /// <returns>null if duplication fails, otherwise the duplicated object</returns> | 2154 | /// <returns>null if duplication fails, otherwise the duplicated object</returns> |
1939 | public SceneObjectGroup DuplicateObject( | 2155 | /// <summary> |
1940 | uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) | 2156 | public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) |
1941 | { | 2157 | { |
1942 | Monitor.Enter(m_updateLock); | 2158 | // m_log.DebugFormat( |
2159 | // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", | ||
2160 | // originalPrimID, offset, AgentID); | ||
1943 | 2161 | ||
1944 | try | 2162 | SceneObjectGroup original = GetGroupByPrim(originalPrimID); |
2163 | if (original != null) | ||
1945 | { | 2164 | { |
1946 | // m_log.DebugFormat( | 2165 | if (m_parentScene.Permissions.CanDuplicateObject( |
1947 | // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", | ||
1948 | // originalPrimID, offset, AgentID); | ||
1949 | |||
1950 | SceneObjectGroup original = GetGroupByPrim(originalPrimID); | ||
1951 | if (original == null) | ||
1952 | { | ||
1953 | m_log.WarnFormat( | ||
1954 | "[SCENEGRAPH]: Attempt to duplicate nonexistent prim id {0} by {1}", originalPrimID, AgentID); | ||
1955 | |||
1956 | return null; | ||
1957 | } | ||
1958 | |||
1959 | if (!m_parentScene.Permissions.CanDuplicateObject( | ||
1960 | original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) | 2166 | original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) |
1961 | return null; | ||
1962 | |||
1963 | SceneObjectGroup copy = original.Copy(true); | ||
1964 | copy.AbsolutePosition = copy.AbsolutePosition + offset; | ||
1965 | |||
1966 | if (original.OwnerID != AgentID) | ||
1967 | { | 2167 | { |
1968 | copy.SetOwnerId(AgentID); | 2168 | SceneObjectGroup copy = original.Copy(true); |
1969 | copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID); | 2169 | copy.AbsolutePosition = copy.AbsolutePosition + offset; |
1970 | |||
1971 | SceneObjectPart[] partList = copy.Parts; | ||
1972 | 2170 | ||
1973 | if (m_parentScene.Permissions.PropagatePermissions()) | 2171 | if (original.OwnerID != AgentID) |
1974 | { | 2172 | { |
1975 | foreach (SceneObjectPart child in partList) | 2173 | copy.SetOwnerId(AgentID); |
2174 | copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID); | ||
2175 | |||
2176 | SceneObjectPart[] partList = copy.Parts; | ||
2177 | |||
2178 | if (m_parentScene.Permissions.PropagatePermissions()) | ||
1976 | { | 2179 | { |
1977 | child.Inventory.ChangeInventoryOwner(AgentID); | 2180 | foreach (SceneObjectPart child in partList) |
1978 | child.TriggerScriptChangedEvent(Changed.OWNER); | 2181 | { |
1979 | child.ApplyNextOwnerPermissions(); | 2182 | child.Inventory.ChangeInventoryOwner(AgentID); |
2183 | child.TriggerScriptChangedEvent(Changed.OWNER); | ||
2184 | child.ApplyNextOwnerPermissions(); | ||
2185 | } | ||
1980 | } | 2186 | } |
1981 | } | 2187 | } |
1982 | 2188 | ||
1983 | copy.RootPart.ObjectSaleType = 0; | 2189 | // FIXME: This section needs to be refactored so that it just calls AddSceneObject() |
1984 | copy.RootPart.SalePrice = 10; | 2190 | Entities.Add(copy); |
1985 | } | ||
1986 | 2191 | ||
1987 | // FIXME: This section needs to be refactored so that it just calls AddSceneObject() | 2192 | lock (SceneObjectGroupsByFullID) |
1988 | Entities.Add(copy); | 2193 | SceneObjectGroupsByFullID[copy.UUID] = copy; |
1989 | |||
1990 | lock (SceneObjectGroupsByFullID) | ||
1991 | SceneObjectGroupsByFullID[copy.UUID] = copy; | ||
1992 | |||
1993 | SceneObjectPart[] children = copy.Parts; | ||
1994 | |||
1995 | lock (SceneObjectGroupsByFullPartID) | ||
1996 | { | ||
1997 | SceneObjectGroupsByFullPartID[copy.UUID] = copy; | ||
1998 | foreach (SceneObjectPart part in children) | ||
1999 | SceneObjectGroupsByFullPartID[part.UUID] = copy; | ||
2000 | } | ||
2001 | |||
2002 | lock (SceneObjectGroupsByLocalPartID) | ||
2003 | { | ||
2004 | SceneObjectGroupsByLocalPartID[copy.LocalId] = copy; | ||
2005 | foreach (SceneObjectPart part in children) | ||
2006 | SceneObjectGroupsByLocalPartID[part.LocalId] = copy; | ||
2007 | } | ||
2008 | // PROBABLE END OF FIXME | ||
2009 | 2194 | ||
2010 | // Since we copy from a source group that is in selected | 2195 | SceneObjectPart[] parts = copy.Parts; |
2011 | // state, but the copy is shown deselected in the viewer, | 2196 | foreach (SceneObjectPart part in parts) |
2012 | // We need to clear the selection flag here, else that | 2197 | { |
2013 | // prim never gets persisted at all. The client doesn't | 2198 | lock (SceneObjectGroupsByFullPartID) |
2014 | // think it's selected, so it will never send a deselect... | 2199 | SceneObjectGroupsByFullPartID[part.UUID] = copy; |
2015 | copy.IsSelected = false; | 2200 | lock (SceneObjectGroupsByLocalPartID) |
2201 | SceneObjectGroupsByLocalPartID[part.LocalId] = copy; | ||
2202 | } | ||
2016 | 2203 | ||
2017 | m_numTotalPrim += copy.Parts.Length; | 2204 | // PROBABLE END OF FIXME |
2018 | 2205 | ||
2019 | // Go through all parts (primitives and meshes) of this Scene Object | 2206 | // Since we copy from a source group that is in selected |
2020 | foreach (SceneObjectPart part in copy.Parts) | 2207 | // state, but the copy is shown deselected in the viewer, |
2021 | { | 2208 | // We need to clear the selection flag here, else that |
2022 | // Keep track of the total number of meshes or geometric primitives now in the scene; | 2209 | // prim never gets persisted at all. The client doesn't |
2023 | // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to | 2210 | // think it's selected, so it will never send a deselect... |
2024 | // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives | 2211 | copy.IsSelected = false; |
2025 | if (part.GetPrimType() == PrimType.SCULPT) | ||
2026 | m_numMesh++; | ||
2027 | else | ||
2028 | m_numPrim++; | ||
2029 | } | ||
2030 | 2212 | ||
2031 | if (rot != Quaternion.Identity) | 2213 | m_numPrim += copy.Parts.Length; |
2032 | { | ||
2033 | copy.UpdateGroupRotationR(rot); | ||
2034 | } | ||
2035 | 2214 | ||
2036 | copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); | 2215 | if (rot != Quaternion.Identity) |
2037 | copy.HasGroupChanged = true; | 2216 | { |
2038 | copy.ScheduleGroupForFullUpdate(); | 2217 | copy.UpdateGroupRotationR(rot); |
2039 | copy.ResumeScripts(); | 2218 | } |
2219 | |||
2220 | copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); | ||
2221 | copy.HasGroupChanged = true; | ||
2222 | copy.ScheduleGroupForFullUpdate(); | ||
2223 | copy.ResumeScripts(); | ||
2040 | 2224 | ||
2041 | // required for physics to update it's position | 2225 | // required for physics to update it's position |
2042 | copy.AbsolutePosition = copy.AbsolutePosition; | 2226 | copy.AbsolutePosition = copy.AbsolutePosition; |
2043 | 2227 | ||
2044 | return copy; | 2228 | return copy; |
2229 | } | ||
2045 | } | 2230 | } |
2046 | finally | 2231 | else |
2047 | { | 2232 | { |
2048 | Monitor.Exit(m_updateLock); | 2233 | m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID); |
2049 | } | 2234 | } |
2235 | |||
2236 | return null; | ||
2050 | } | 2237 | } |
2051 | 2238 | ||
2052 | /// <summary> | ||
2053 | /// Calculates the distance between two Vector3s | 2239 | /// Calculates the distance between two Vector3s |
2054 | /// </summary> | 2240 | /// </summary> |
2055 | /// <param name="v1"></param> | 2241 | /// <param name="v1"></param> |